Skip to Content
Grab N GoTypeScript

TypeScript

Syntax

Primitives
let name: string = 'Tammy' let age: number = 28 let active: boolean = true let nothing: null = null let missing: undefined = undefined
Arrays & Tuples
let ids: number[] = [1, 2, 3] let names: Array<string> = ['a', 'b'] // tuple — fixed length, typed positions let pair: [string, number] = ['age', 28]
Objects
// inline let user: { name: string; age: number } = { name: 'Tammy', age: 28, } // optional property let config: { debug?: boolean } = {}
Interfaces
interface User { id: number name: string email?: string // optional } const user: User = { id: 1, name: 'Tammy' }
Type Aliases
type ID = string | number type Status = 'loading' | 'error' | 'success' type Point = { x: number; y: number } let userId: ID = 42 let state: Status = 'loading'
Functions
function add(a: number, b: number): number { return a + b } const greet = (name: string): string => { return `Hello ${name}` } function log(msg: string, level?: string) {}
Enums
enum Status { Idle, // 0 Loading, // 1 Success, // 2 Error, // 3 } // string enum — more readable in logs enum Dir { Up = 'UP', Down = 'DOWN', }
Unknown vs Any
// any — disables type checking (avoid) let a: any = 'hello' a.foo.bar // no error, but unsafe // unknown — must narrow before using let b: unknown = 'hello' if (typeof b === 'string') { b.toUpperCase() // safe after check }

Beginner Patterns

Union Types
let id: string | number = 'abc' id = 42 // also valid function show(val: string | number) { if (typeof val === 'string') { val.toUpperCase() // TS knows it's string } }
Intersection Types
type HasName = { name: string } type HasAge = { age: number } // combine — must have ALL properties type Person = HasName & HasAge const p: Person = { name: 'Tammy', age: 28 }
Type Narrowing
function handle(val: string | number) { if (typeof val === 'string') { val.toUpperCase() // string methods } else { val.toFixed(2) // number methods } } function greet(name?: string) { if (name) { name.toUpperCase() // definitely string } }
Type Assertion
// tell TS you know the type const input = document.getElementById('name') as HTMLInputElement input.value // no error // non-null assertion (careful) const el = document.querySelector('.btn')!
Typeof / Keyof
const config = { debug: true, port: 3000 } // typeof — extract type from a value type Config = typeof config // { debug: boolean; port: number } // keyof — union of keys type ConfigKey = keyof Config // 'debug' | 'port'
Generics
function first<T>(arr: T[]): T | undefined { return arr[0] } first<number>([1, 2, 3]) // 1 first(['a', 'b']) // 'a' (inferred)

Intermediate Patterns

Utility Types
interface User { id: number name: string email: string } Partial<User> // all optional Required<User> // all required Pick<User, 'id' | 'name'> // subset Omit<User, 'email'> // exclude Readonly<User> // immutable Record<string, number> // { [key]: num }
Overloads
function format(val: string): string function format(val: number): string function format(val: string | number): string { if (typeof val === 'string') return val.trim() return val.toFixed(2) } format('hello') // string signature format(3.14159) // number signature
Discriminated Union
type Result = | { status: 'ok'; data: string } | { status: 'error'; message: string } function handle(r: Result) { switch (r.status) { case 'ok': r.data // TS knows data exists break case 'error': r.message // TS knows message exists break } }
Generic Constraints
// T must have a length property function longest<T extends { length: number }>( a: T, b: T ): T { return a.length >= b.length ? a : b } longest('abc', 'de') // 'abc' longest([1, 2], [1]) // [1, 2]

Advanced Patterns

as const
const routes = ['/', '/about', '/blog'] as const // readonly ['/', '/about', '/blog'] type Route = (typeof routes)[number] // '/' | '/about' | '/blog' const config = { env: 'prod', port: 3000 } as const // { readonly env: 'prod'; readonly port: 3000 }
Type Guards
interface Dog { bark(): void } interface Cat { meow(): void } // custom guard — returns `is` type function isDog(pet: Dog | Cat): pet is Dog { return 'bark' in pet } const pet: Dog | Cat = getPet() if (isDog(pet)) { pet.bark() // TS knows it's Dog }
Satisfies
type Colors = Record<string, string | string[]> // validates type without widening const palette = { red: '#ff0000', blue: ['#0000ff', '#0033cc'], } satisfies Colors // TS still knows red is string, blue is string[] palette.red.toUpperCase() // works palette.blue.map(c => c) // works
Mapped Types
type Optional<T> = { [K in keyof T]?: T[K] } type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] } type UserGetters = Getters<{ name: string; age: number }> // { getName: () => string; getAge: () => number }
Last updated on