Skip to content

Instantly share code, notes, and snippets.

@RJ-software-outsourcing
Last active June 4, 2020 06:31
Show Gist options
  • Save RJ-software-outsourcing/82945cbd747a37df1bbc5f3b0044494b to your computer and use it in GitHub Desktop.
Save RJ-software-outsourcing/82945cbd747a37df1bbc5f3b0044494b to your computer and use it in GitHub Desktop.

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!

Pros

  • 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

Cons

  • 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)

For those NPM modules without type definition built-in, we install it from @types on npm

npm install styled-components
npm install @types/styled-components

Basic types

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 />

Hooks

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])

Event Handlers

<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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment