Here's a quick way to start a typescript project:
npx create-react-app demo-app --template typescript
- TypeScript is a superset of JavaScript
- Before execution, TypeScript code will be compiled to JavaScript (by TypeScript compiler)
- TypeScript compiler is written in TypeScript!
- increase readability
- More likely to write quality code
- feel more confidence to do large refactoring
- VS code has great support for TypeScript
- TS compiler is following up to the latest ECMA spec
- Might slows you down a bit
- Type support for third party libraries might be missing or outdated
- Error message can be very difficult to understand (especially those from 3-party libs)
npm install styled-components
npm install @types/styled-components
Boolean
const isOpen : boolean = false;
Number
let age : number = 100;
String
const name : string = 'David 8';
Array
const arr1 : number[] = [1, 3, 5];
const arr2 : Array<number> = [2, 4, 6];
Tuple
and Enum
can be very useful (which JS doesn't have)
Tuple
const secret : [string, number] = ['thank you', 9527];
Enum
enum MODULES {
PRODUCT = 'product',
OPERATION = 'operation'
}
let selected : MODULES = MODULES.PRODUCT;
selected = 'product'; // this will fail, despite the value matches MODULES.PRODUCT
or alternatively we can do:
const PRODUCT : string = 'product';
const OPERATION : string = 'operation';
type MOUDLES = typeof PRODUCT | typeof OPERATION;
let selected : MOUDLES = PRODUCT;
selected = 'operation'; // passing identical value will work this time
Function
enum PERMISSION {
READ = 'read',
WRITE = 'write',
}
interface User {
name : string,
email : string,
active : boolean,
permissions : Array<PERMISSION>,
}
export const isAbleToRead = (user : User) : boolean => {
const { active, permissions } = user;
return active && permissions.some((permission) => permission === PERMISSION.WRITE)
}
an example of return value validation
interface User {
balance : number,
name : string,
active : boolean,
}
export const ableToTransferMoney = (user : User) : boolean => {
const { active, balance } = user;
return balance && active;
}
type a = { aaa : number, ccc : string };
type b = { bbb : number, ccc : string }
export const haha = (val : a | b) => {
const { aaa, bbb, ccc } = val; // either aaa or bbb does not exist
if (val.aaa) { // even if you do this, it's still not legal
}
const t = ccc; // ccc is the common property of type a and type b;
}
unless you cast it by yourself, but then it won't be as robust
export const haha = (val : a | b) => {
if ((val as a).aaa > 10) {
} else if ((val as b).bbb < 0) {
}
}
VS code can be very thoughtful if we are using TypeScript
const getLength = (val : string | null) => {
const t = value?.length; // ? will be added automatically by VS code
}
const getLength2 = (val : string | undefined) => {
const t = value?.length; // ? will be added automatically by vs code
}
State & Props for Class components
interface AvatarProps {
userId : string,
small? boolean,
}
interface AvatarState {
url : string,
}
class Avatar extends React.Component<AvatarProps, AvatarStates> {
// yeah...
}
btw, the error message can be very nasty if we're not doing setState properly
Props for functional components
const Avatar = ({ userId, small } : AvatarProps) => <img />);
// Or we can use object literal
const Avatar = (
{ userId, small } : { userId : string, small? : boolean }
) => <img />
useState
const [isOpen, toggleModal] = useState<boolean>(false);
toggleModal('oh yeah'); // this will fail
useEffect
// There's no need to pass type to useEffect, although it does check the type of returning function inside of useEffect
useEffect(() => {
return async () => undefined; // wrong! you can't return a promise here.
}, []);
useRef
const inputEl = useRef<HTMLInputElement>(null);
useMemo
const setValue = useMemo((field : string, value : any) : void => {
dispatch(setProductAttribute(productId, field, value))
}, [productId])
<input
onClick={(e: React.MouseEvent) => e.movementX }
onFocus={(e: React.FocusEvent) => undefined}
onChange={(e : React.ChangeEvent) => undefined}
/>
You can also specify the type of DOM that fires the event
const doSomethingWhenHoveringTextarea = (
e: React.MouseEvent<HTMLTextAreaElement>
) => {};
<textarea onMouseMove={doSomethingWhenHoveringTextarea} /> // OK
<div onMouseMove={doSomethingWhenHoveringTextarea} /> // INVALID
Styled-components
const Test = styled.div<{ onHover : boolean }>`
color: ${p => p.onHover ? '' : ''};
`;
If you forget to have onHover
included in your props, the error message will be nasty too
It works if the element is generated by styled-components
const Test = styled.textarea<{ onHover? : boolean }>`
color: ${p => p.onHover ? '' : ''};
`;
const eventHandler = (e : React.MouseEvent<HTMLDivElement>) => {};
<Test onMouseMove={eventHandler} /> // We are still able to identify element type even it's from styled-components