“Hands-On with
Advanced TypeScript Types”
[EN]

Illarion Koperski

2025-03-12

@illarionvk

Beyond "ANY":

Closing The Type/Runtime Gap

  • Avoid type assertions
  • Use local window declarations
  • Use easy exhaustiveness checks
  • Implement critical type resets
  • Prefer type aliases to interfaces

Avoid Type Assertions

// Before

const a = JSON.parse('1') as string

// true at compile,
// but false at runtime
typeof a === 'string'
// After

const _b = JSON.parse('1')

const b: number | null =
typeof _b === 'number' ? _b : null

Local window declaration

// Before

declare global {
  interface Window {
    myGlobalStuff?: {
      id: string
    }
  }
}

const id = window.myGlobalStuff?.id
// After

type CustomWindow = {
  myGlobalStuff?: {
    id: string
  }
} & Window

declare let window: CustomWindow

const id = window.myGlobalStuff?.id

Easy Exhaustiveness Check

export const infer = (input: 'a' | 'b' | 'c') => {
  switch (input) {
    case 'a':
      return 'x'
    case 'b':
      return 'x'
    default:
      // @ts-expect-error We forgot to handle 'c'
      input satisfies never
      return 'z'
  }
}

Critical Type Resets

https://www.totaltypescript.com/ts-reset

Interfaces 🤷‍♂️

interface MyThing {
  id?: string
}

interface MyThing {
  name?: string
}

const a: MyThing = { id: '1' }
const b: MyThing = { name: 'Larry' }
const c: MyThing = { id: '1', name: 'Larry' }

// LOOK MA, NO ERRORS!

Business Logic With Types

github.com/illarionvk/warsawjs-2025-02-typescript

Game Loop Diagram

Q & A

Can we adopt Typescript gradually?

Can I build a chess game with this thing?
What about branded types?

See you next month at WarsawJS

Hands-On with Advanced TypeScript Types

By Illarion Koperski

Hands-On with Advanced TypeScript Types

  • 68