Code

TS Cheatsheet

Types by Inference

const program = "Hello World"
        
// %inferred type: string

Type annotations

const numberToString = (value: number) : string => String(value)

console.log(numberToString(333))

/**
  [LOG]: "333" 
**/

Interfaces

Use interface if exporting so that consumers can extend.

interface Point {
  x: number;
  y: number;
}
 
const logPoint = (p: Point) => console.log(`${p.x}, ${p.y}`)

logPoint({ x: 333, y: 999})

/**
  [LOG]: "333, 999"
**/
interface PersonInterface {
    name: string
    gender: string
}

interface EmployeeInterface extends PersonInterface {
    code: number
}

const person: EmployeeInterface = {
    name: "Josoroma",
    gender: "M",
    code: 1,
}

console.log(person)

/**
  [LOG]: {
    "name": "Josoroma",
    "gender": "M",
    "code": 1
  } 
**/
interface Component {
    w: number
    h: number
    enableEvents(enable: boolean): void
}

interface Button extends Component {
    label: string
}

class RadioButton implements Button {
    h: number
    w: number
    label: string
    private enable: boolean = false

    constructor(h: number, w: number, label: string) {
        this.h = h;
        this.w = w;
        this.label = label;
    }

    enableEvents(enable: boolean): void {
        this.enable = enable;
    }
}

const radioButton: Button = new RadioButton(100, 20, "test")

radioButton.enableEvents(true)

console.log(radioButton)

/**
  [LOG]: RadioButton: {
    "enable": true,
    "h": 100,
    "w": 20,
    "label": "test"
  }
**/

Intersect types

type FirstNameType = {
    firstName: string
}

type LastNameType = {
    lastName: string
}

type FullnameType = FirstNameType & LastNameType

const some: FullnameType = {
    firstName: 'Jos',
    lastName: 'oRoma',
}

console.log(some)

/**
  [LOG]: {
    "firstName": "Jos",
    "lastName": "oRoma"
  } 
**/

Explicit object shape using types and interfaces

/** unions with exact string literal **/

type LanguageType = 'en' | 'fr' | 'es'

interface ComponentPropsInterface {
  id: string
  name: string
  age: number
  disabled: boolean
  optional?: number[]
  lang: LanguageType
  children: ReactNode
  onChange?: FormEventHandler<HTMLInputElement>
}

export Component(props: ComponentPropsInterface) {
  const {id, name, age, disabled, lang} = props
  return (
    <>
      { children }
    </>
  );
}

As a function type

interface KeyInterface
{
    (key: string, value: boolean): void
}

const addKeyValue = (key: string, value: boolean): void => { 
    console.log(`addKeyValue: key = ${key}, value = ${value}`)
}

const updateKeyValue = (key: string, value: boolean): void => { 
    console.log(`updateKeyValue: key = ${key}, value = ${value}`)
}
    
let attr: KeyInterface = addKeyValue

attr('disabled', true)

attr('enabled', false) 

attr = updateKeyValue

attr('disabled', false) 

/**
  [LOG]: "addKeyValue: key = disabled, value = true" 
  [LOG]: "addKeyValue: key = enabled, value = false" 
  [LOG]: "updateKeyValue: key = disabled, value = false" 
**/

Objects

interface ObjectProps {
  /** array of strings */
  names: string[]

  /** any object (NOT COMMON but useful as placeholder) **/
  obj: object

  /** almost the same as `object`, exactly the same as `Object` **/
  obj2: {}

  /** an object with any number of properties (PREFERRED) **/
  obj3: {
    id: string
    title: string
  }

  /** array of objects! (common) **/
  objArr: {
    id: string
    title: string
  }[]
}

Dictionaires

interface DictionaryProps {
  /** a dict object with any number of properties of the same type **/
  dict1: {
    [key: string]: boolean
  }

  /** equivalent to dict1 **/
  dict2: Record<string, boolean>
}
type Book = {
  title: string
  description: string
}

const bookDictionary: { [key: number]: Book } = {}

// Create book
bookDictionary[1] = {
    title: 'The Law',
    description: 'Originally published as a pamphlet, in 1850 by Frederic Bastiat.'
}

console.log(bookDictionary)

/**
  [LOG]: {
      "1": {
      "title": "The Law",
      "description": "Originally published as a pamphlet, in 1850 by Frederic Bastiat."
    }
  } 
**/

Utility types

interface Book {
  name: string
  description?: string
  year: number
}

Partial (Optional)


We can see:

  • That two fields are required: name and year.
  • The description field is optional.

When would you use a Partial?

Helpful when you are required to use only certain fields.

When we have a row of a table that represents in its columns the different fields of a record that can be updated, it can be any of the fields, so you don’t mind assuming that all fields may be ultimately optional seen as optional.

How partial works:

type Partial<T> = {
  [P in keyof T]?: T[P]
};

It just defines a new object type which copies all properties of T as optional.

Required ()

interface Book {
  id?: string
  name: string
}

We can use this Book interface skipping the ID when creating the book. On the other hand, when we are required to update the book, we want to make sure the ID is set.

Using Map in TypeScript

type JobInfo = {
    language: string
    workExperience: number
}

type JobPosition = 'Frontend' | 'Backend'

const dictionaryJob = new Map<JobPosition, JobInfo>()

dictionaryJob.set('Frontend', {
    language: 'JavaScript',
    workExperience: 5
})

dictionaryJob.set('Backend', {
    language: 'Python',
    workExperience: 4
})

console.log(dictionaryJob)

/**
  [LOG]: Map (2) {"Frontend" => {
    "language": "JavaScript",
    "workExperience": 5
  }, "Backend" => {
    "language": "Python",
    "workExperience": 4
  }} 
**/

React Events

const handleOnChange = async (e: FormEvent<HTMLInputElement>) => {
    if (!e.target.files) {
      return;
    }

    // handle the input...
    console.log(e.target.files);
}

return (
  <>
    <input type="text" value="my value" onChange={handleOnChange} />
  </>
)

Typing default props

// using typeof as a shortcut; note that it hoists!
type GreetProps = { age: number } & typeof defaultProps

const defaultProps = {
  age: 21,
}

const Greet = (props: GreetProps) => {
  return props
}

Greet.defaultProps = defaultProps

console.log(Greet.defaultProps)

/**
  [LOG]: {
    "age": 21
  }
**/

Function Components

interface AppProps {
  message: string;
}

// declare a Function Component; return type is inferred.
const App = (props: AppProps) => <>{ props.message }</>

// inline the type declaration; eliminates naming the prop types, but looks repetitive.
const App = (props: { message: string }) => <>{ props.message }</>

// annotate the return type, so an error is raised if you accidentally return some other type.
const App = (props: AppProps): JSX.Element => <>{ props.message }</>

Hooks

// many hooks are initialized with null-ish default values.

const [user, setUser] = useState<UserInterface | null>(null)
// if a state is initialized soon after setup and always has a value after.
const [user, setUser] = React.useState<UserInterface>({} as UserInterface);

useEffect and useRef

const Foo = () => {
  // - If possible, prefer as specific as possible. For example, HTMLDivElement
  //   is better than HTMLElement and way better than Element.
  // - Technical-wise, this returns RefObject<HTMLDivElement>
  const divRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    // Note that ref.current may be null. This is expected, because you may
    // conditionally render the ref-ed element, or you may forgot to assign it
    if (!divRef.current) throw Error("divRef is not assigned")

    // Now divRef.current is sure to be HTMLDivElement
    doSomethingWith(divRef.current)
  }, []);

  // Give the ref to an element so React can manage it for you.
  return <div ref={divRef}>etc</div>
}

If you are sure that divRef.current will never be null, it is also possible to use the non-null assertion operator !

const divRef = useRef<HTMLDivElement>(null!)

// Later... No need to check if it is null.
doSomethingWith(divRef.current)