- Docker.Taipei 共同發起人
- Hacking Thursday 值日生
- COSCUP 開源工作坊講者
- PyCon APAC 講者
- MOPCON 講者
- 熟悉技能
- Linux, Docker, Azure, AWS
- Vim, Emacs, VSCode, Git
- Clojure, Python, Ramda.js, Lodash
- TypeScript, ES2015, React, Redux
- GitHub: https://github.com/bcbcarl
tsc
is written in TypeScript.let isDone: boolean = false; // Boolean // Number let decimal: number = 6; let hex: number = 0xf00d; let binary: number = 0b1010; let octal: number = 0o744; let fullName: string = `Carl Su`; // String let sentence: string = `Hello, my name is ${fullName}.`; let list: Array<number> = [1, 2, 3]; // Array let x: [string, number]; // Tuple x = ["hello", 10];
// Enum enum Color { Red = 1, Green = 2, Blue = 4 } let c: Color = Color.Green; // Any let notSure: any = 4; notSure = "maybe a string instead"; // Void const warnUser = (): void => alert("This is my warning message"); // Type assertions let someValue: any = "this is a string"; let strLength: number = (someValue as string).length;
npm install -g tslint typescript npm init touch index.ts tslint --init tslint index.ts tsc --init tsc
const add10 = (x: number) => x + 10; console.log(`add10(3): ${add10(3)}`);
var add10 = function (x) { return x + 10; }; console.log("add10(3): " + add10(3));
tslint.json
:
{ "rules": { "class-name": true, "comment-format": [ true, "check-space" ], ... } }
tsconfig.json
:
{ "compilerOptions": { "module": "commonjs", "target": "es5", "noImplicitAny": false, "sourceMap": false }, "exclude": [ "node_modules" ] }
https://www.typescriptlang.org/docs/handbook/tsconfig-json.html
Browserify
npm install tsify browserify main.ts -p [ tsify --noImplicitAny ] > bundle.js
webpack
npm install ts-loader --save-dev
https://www.typescriptlang.org/docs/handbook/integrating-with-build-tools.html
tsc -d
generates corresponding '.d.ts' file.
index.ts
:
const add10 = (x: number) => x + 10;
index.d.ts
:
declare const add10: (x: number) => number;
The repository for high quality TypeScript type definitions.
Get the definitions:
# Search for definitions. typings search tape # Find a definition by name. typings search --name react # Install non-global typings (defaults to "npm" source). typings install debug --save # Install with `--global`. typings install dt~mocha --global --save # Search and install by version. typings info env~node --versions typings install env~node@6.0 --global --save
npm
- dependencies from NPMgithub
- dependencies directly from GitHub (E.g. Duo, JSPM)bitbucket
- dependencies directly from Bitbucketbower
- dependencies from Bowercommon
- "standard" libraries without a known "source"shared
- shared library functionalitylib
- shared environment functionality (mirror of shared
) (--global
)env
- environments (E.g. atom
, electron
) (--global
)global
- global (window.<var>
) libraries (--global
)dt
- typings from DefinitelyTyped (usually --global
)
React makes it painless to create interactive UIs.
Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes.
Declarative views make your code more predictable, simpler to understand, and easier to debug.
Build encapsulated components that manage their own state, then compose them to make complex UIs.
Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep state out of the DOM.
We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code.
React can also render on the server using Node and power mobile apps using React Native.
JSX is a JavaScript syntax extension that looks similar to XML.
You can use a simple JSX syntactic transform with React.
var Nav; // Input (JSX): var app = <Nav color="blue" />; // Output (JS): var app = React.createElement(Nav, {color:"blue"});
A set of React components implementing Google's Material Design specification with the power of CSS Modules.
import React from 'react'; import ReactDOM from 'react-dom'; import { Button } from 'react-toolbox/lib/button'; ReactDOM.render( <Button label="Hello World!" />, document.getElementById('app') );
import React from 'react'; import styles from './table.css'; export default class Table extends React.Component { render () { return <div className={styles.table}> <div className={styles.row}> <div className={styles.cell}>A0</div> <div className={styles.cell}>B0</div> </div> </div>; } }
<div class="table__table___32osj"> <div class="table__row___2w27N"> <div class="table__cell___1oVw5">A0</div> <div class="table__cell___1oVw5">B0</div> </div> </div>
camelCase
CSS class names.styles
object whenever constructing a className.Seamless mapping of class names to CSS modules inside of React components.
camelCase
naming convention.styles
object every time you use a
CSS Module.<div className='global-css' styleName='local-module'></div>
/* styles.css */ @value primary: red; .myClass { color: primary; }
/* styles.css.d.ts */ export const primary: string; export const myClass: string;
/* app.ts */ import * as styles from './styles.css'; console.log(`<div class="${styles.myClass}"></div>`); console.log(`<div style="color: ${styles.primary}"></div>`);
import * as React from "react"; export interface HelloProps { compiler: string; framework: string; } export class Hello extends React.Component<HelloProps, {}> { render() { return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>; } }
import * as React from "react"; export class Hello extends React.Component { render() { return React.createElement( "h1", null, "Hello from ", this.props.compiler, " and ", this.props.framework, "!"); } }
Migrating from JavaScript to TypeScript:
.jsx?
to .tsx?
.any
.any
as possible.declare module "humps";
).declare module "*.css";
).https://basarat.gitbooks.io/typescript/content/docs/types/migrating.html
Including .jsx?
files with --allowJs
:
tsconfig.json
:
{ "compilerOptions": { "module": "es2015", "target": "es2015", "allowJs": true, } }
https://medium.com/@clayallsopp/incrementally-migrating-javascript-to-typescript-565020e49c88
Our code must manage more state than ever before.
This complexity is difficult to handle as we're mixing two concepts that are very hard for the human mind to reason about: mutation and asynchronicity.
Redux attempts to make state mutations predictable by imposing certain restrictions on how and when updates can happen.
These restrictions are reflected in the three principles of Redux.
Redux can be described in three fundamental principles:
The state of your whole application is stored in an object tree within a single store.
console.log(store.getState());
{ visibilityFilter: 'SHOW_ALL', todos: [{ text: 'Consider using Redux', completed: true, }, { text: 'Keep all state in a single tree', completed: false }] }
The only way to change the state is to emit an action, an object describing what happened.
store.dispatch({ type: 'COMPLETE_TODO', index: 1 }) store.dispatch({ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_COMPLETED' })
To specify how the state tree is transformed by actions, you write pure reducers.
export const todos = (state = [], action) => { switch (action.type) { case 'ADD_TODO': return state; case 'COMPLETE_TODO': return state; default: return state; } }
import { combineReducers, createStore } from 'redux'; import { visibilityFilter, todos } from './reducers'; let reducer = combineReducers({ visibilityFilter, todos }); let store = createStore(reducer);
We will write our 'Hello, world' version for Sagas.
Create a file sagas.ts
then add the following snippet:
export function* helloSaga(): IterableIterator<void> { console.log("Hello Sagas!"); }
https://yelouafi.github.io/redux-saga/docs/introduction/BeginnerTutorial.html
In order to run our Saga, we need to:
We will make the changes to main.tsx
:
import { createStore, applyMiddleware } from "redux"; import createSagaMiddleware from "redux-saga"; import { helloSaga } from "./sagas"; const sagaMiddleware = createSagaMiddleware(); const store = createStore(reducer, applyMiddleware(sagaMiddleware)); sagaMiddleware.run(helloSaga);
We'll provide an additional callback onIncrementAsync
to the UI component Counter.tsx
:
interface CounterProps { value: number; onIncrement(): { type: string }; onDecrement(): { type: string }; onIncrementAsync(): { type: string }; } const Counter = ({value, onIncrement, onDecrement, onIncrementAsync}: CounterProps) => <div> {" "} <button onClick={onIncrementAsync}>Increment after 1 second</button> <hr /> <div>Clicked: {value} times</div> </div>
We should connect the onIncrementAsync
of the Component to a Store action.
We will modify the main.tsx
module as follows:
function render() { ReactDOM.render( <Counter onIncrementAsync={() => action("INCREMENT_ASYNC")} />, document.getElementById("root") ); }
Add the following code to the sagas.ts
module:
import { takeEvery, delay } from "redux-saga"; import { call, put, Effect } from "redux-saga/effects"; // Our worker Saga: will perform the async increment task export function* incrementAsync(): IterableIterator<Effect> { yield call(delay, 1000); yield put({ type: "INCREMENT" }); } // Our watcher Saga: spawn a new task on each INCREMENT_ASYNC export function* watchIncrementAsync() { yield* takeEvery("INCREMENT_ASYNC", incrementAsync); }
Now we have 2 Sagas, and we need to start them both at once.
To do that, we'll add a rootSaga
that is responsible for starting our
other Sagas.
In the same file sagas.ts
, add the following code:
// single entry point to start all Sagas at once export default function* rootSaga() { yield [ helloSaga(), watchIncrementAsync() ]; }
This Saga yields an array with the results of calling our two sagas,
helloSaga
and watchIncrementAsync
.
Now we only have to invoke sagaMiddleware.run
on the root Saga in main.tsx
:
import rootSaga from "./sagas"; const sagaMiddleware = createSagaMiddleware(); const store = createStore(...); sagaMiddleware.run(rootSaga);