Comparisons of ways of typing in TypeScript

2023-10-01

Direct type annotations

const game: Game = {
	name: "League of Legends",
	genre: "MOBA"
}

Use case

  • When you want to explicitly define the type of a variable.
  • When you want to leverage TypeScript’s type checking to catch errors early.
  • Type Assertions

    const notes = await fetchNotes() as Promise<Note[]>

    Use case

  • When dealing with data from external sources (e.g., APIs) where you are confident about the type but TypeScript cannot infer it.
  • When you need to override TypeScript’s inferred type for specific reasons.
  • Avoid type assertions as much as possible. Only use it when you are sure that the type you are sure that the type you are asserting is valid.
  • Satisfies Operator

    import type { SomeConfig } from 'lib';
    
    const cfg = {
    	db: "postgres",
    	username: "asdf",
    	// ...
    } as const satisfies SomeConfig

    Use case

  • Used to ensure that a value conforms to a specific type without changing the inferred type of the value. It’s useful for checking that an object matches a specific shape or type while retaining its original inferred type for further operations.
  • When you want to ensure that an object matches a specific type without altering its original inferred type.
  • When you want to enforce certain constraints while preserving the flexibility of the original type inference.
  • Typically good used for config files, when you want to make sure that your variable satisfies the type of the config. Using it with as const is useful in narrowing down the type from whatever the type was defined in the config type to the actual value - eg. instead of string as the type for username, it will be inferred as "asdf" .