Skip to content

Instantly share code, notes, and snippets.

@antoniojps
Last active December 6, 2021 00:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save antoniojps/c05f5cb0ce44fa0f64c3ce7ea0a7c474 to your computer and use it in GitHub Desktop.
Save antoniojps/c05f5cb0ce44fa0f64c3ce7ea0a7c474 to your computer and use it in GitHub Desktop.
Typescript cheatsheet

Check the typescript handbook

Core types

// enum
enum Role {
  ADMIN,
  READ_ONLY,
  AUTHOR
}

// object
type Person = {
  readonly id: string | number; // readonly, cannot be re-assigned
  firstName: string; // string
  lastName: string; // string
  fullName: (firstName: string, lastName: string ) => string; // function with two params string and returns string
  age: number; // number
  month: number | string; // union
  hobbies: string[]; // array
  childBornAt: (number | string)[]; // array of string or number
  keyValuePair: [string, number]; // turple: we are sure the first element is a string and the second number
  role: Role;
  callback: (num: number) => void; // function that doesnt return anything
}

Interfaces

For objects this is preferable

interface Indexed {
  readonly id: string | number;
}

interface Named {
  firstName: string; // string
  middleName?: string; // optional
  lastName: string; // string
}

interface Greetable extends Named, Indexed {
  greet: (name: string) => string
}

// use it like so
const Manel: Greetable = {
  id: 123,
  firstName: 'Manel',
  lastName: 'Paiva',
  greet: (name) => `Hello ${name}`
}

Can also be used for function types

interface AddFn {
  (a: number, b: number): number
}
const add : AddFn = (a, b) => a + b

Intersection types

type Admin = {
  name: string
  priviliges: string[]
}

type Employee = {
  name: string
  startDate: Date
}

// in objects combines them
type ElevatedUser = Employee & Admin

const admin: ElevatedUser = {
  name: 'Joao',
  priviliges: ['delete users'],
  startDate: new Date()
}

type Combinable = string | number
type Numeric = number | boolean

// in union types intersects whats in common
type Universal = Combinable & Numeric // number

Type guards

function add(a: Combinable, b: Combinable) {
  // check if its a string before adding
  if (typeof a === 'string' || typeof b === 'string') {
    return a.toString() + b.toString()
  }
  return a + b
}

Objects

type UnknownEmployee = Employee | ElevatedUser

function printEmployeeInformation(emp: UnknownEmployee) {
  console.log('Name: ', emp.name)
  // check if the UnknownEmployee has the priviliges key
  if ('priviliges' in emp) {
    console.log('Privileges: ', emp.priviliges)
  }
}

Class instances

class Car {
  drive() {
    console.log('Driving...')
  }
}

class Truck {
  drive() {
    console.log('Driving...')
  }
  loadCargo(ammount: number): void {
    console.log('Loading: ', ammount)
  }
}

type Vehicle = Car | Truck
const mercedez = new Car()
const man = new Truck()

function useVehicle(vehicle: Vehicle) {
  vehicle.drive()
  // check if the vehicle is an instance of truck
  if (vehicle instanceof Truck) vehicle.loadCargo(2000)
}

Type casting

// this element is of type `HTMLInputElement` and will never be null `!`
const userInputElement = <HTMLInputElement>document.getElementById('user-input')!

// alternative to prevent conflicts with JSX
const userInputElementAlt = document.getElementById('user-input') as HTMLInputElement

// alternative to use `!`
if (userInputElementAlt) {
  (userInputElementAlt as HTMLInputElement).value = 'Hi there'
}

Index properties

I dont know the property names but the property name and value must be a string, allows for "dynamic object types".

interface ErrorContainer {
  [prop: string]: string;
}

const errorBag: ErrorContainer = {
  email: 'Not a valid email',
  username: 'Must start with a capital character!'
}

Function overloads

Telling typescript the different combinations you might support in your function

function add (a: number, b: number): number
function add (a: string, b: string): string
function add (a: number, b: string): string
function add (a: string, b: number): string
function add(a: Combinable, b: Combinable) {
  // check if its a string before adding
  if (typeof a === 'string' || typeof b === 'string') {
    return a.toString() + b.toString()
  }
  return a + b
}

const result = add(1, 'Manel')
result.split(' ')

Optional chaining

// imagine this data was coming from an API:
const data = {
  id: 'u1',
  name: 'Antonio',
  job: {
    // title: 'CEO',
    description: 'My own company'
  }
}

// will only log data.job.title if it exists
console.log(data?.job?.title)
// in javascript:
console.log(data && data.job && data.job.title)

Nullish coalescing operator (I can't say this)

A logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, prevents unexpected behaviors.

// if you use || to provide some default value to another variable foo
//, you may encounter unexpected behaviors if you consider some falsy values as usable (eg. '' or 0).
const foo = null ?? 'default string';
console.log(foo);
// expected output: "default string"

const baz = 0 ?? 42;
console.log(baz);
// expected output: 0

Generics

Get additional type information Array<string> array of strings, Promise<string> promise that resolves a string...

const names = Array<string> = []; // string[]
const promise: Promise<string> = new Promise((resolve) => {
  setTimeout(() => {
    resolve('yoo')
  }, 2000)
})

Custom:

function merge<T extends object, U extends object>(objectA: T, objectB: U) {
  return Object.assign(objectA, objectB)
}

interface Lengthy {
  length: number;
}

const countAndDescribe = <T extends Lengthy>(element: T): [T, string] => {
  let descriptionText = 'Got no value'
  if (element.length === 1) descriptionText = 'Got 1 element'
  else if (element.length > 1) descriptionText = `Got ${element.length} elements`
  return [element, descriptionText]
}

keyof constraint:

function extractAndConvert<T extends Object, U extends keyof T>(obj: T, key: U) {
  return obj[key]
}

Partial type:

interface User {
  name: string;
}

function createUser(name: string): User {
  // in the end it will become of type User
  let newUser: Partial<User> = {}
  newUser.name = name
  // type casting to type User
  return newUser as User
}

Readonly type

// you can't change later: extra strictness
const admins: Readonly<string[]> = ['Antonio', 'Manel']
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment