Basics
About
TypeScript adds static types to JavaScript; types are erased at build time.
tsc 7 is the native compiler; defaults are strict, module: esnext and target: es2025.
See: TypeScript Handbook
Basic types
Primitives
| Type | Example |
|---|---|
string | 'Ada' |
number | 42 |
boolean | true |
bigint | 42n |
symbol | Symbol('id') |
null / undefined | null |
object | { id: 1 } |
Special types
| Type | Meaning |
|---|---|
any | opts out of checking |
unknown | top type; safe any, narrow first |
void | no return value |
never | bottom type; unreachable |
let tags: string[] = ['a', 'b']
let pair: [string, number] = ['a', 1]
let id: string | number = 1
let input: unknown = JSON.parse(json)
function fail(msg: string): never {
throw new Error(msg)
}
See: Everyday types
Enums
enum Color {
Red,
Green = 4,
}
let c: Color = Color.Green
Numeric enums are union enums; enums are not erasable syntax.
See: Enums
Declarations
const pi = 3.14 // type 3.14, not number
let total: number = 0
function add(a: number, b: number): number {
return a + b
}
const double = (n: number) => n * 2
Type assertions
declare const value: unknown
const input = value as string
const len = (input as string).length
const upper = (<string>value).toUpperCase() // not in .tsx
as is preferred; angle brackets do not work in .tsx files.
See: Type assertions
Interfaces
Inline
function printLabel(options: { label: string }) {
console.log(options.label)
}
See: Object types
Explicit
interface LabelOptions {
label: string
}
function printLabel(options: LabelOptions) {
console.log(options.label)
}
See: Object types
Optional properties
interface User {
name: string
age?: number
}
See: Optional properties
Readonly properties
interface User {
readonly id: number
}
See: Readonly properties
Index signatures
interface Dict {
[key: string]: unknown[]
}
Same shape as Record<string, unknown[]>.
See: Index signatures
Type aliases
Aliases
type Name = string | string[]
type Point = { x: number; y: number }
See: Type aliases
Intersections
interface Colorful { color: string }
interface Circle { radius: number }
type ColorfulCircle = Colorful & Circle
See: Intersection types
Literal types
type Direction = 'north' | 'south'
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6
const point = { x: 4, y: 2 } as const
// point: { readonly x: 4; readonly y: 2 }
See: Literal types
Type operators
Indexed access
interface Building {
room: {
door: string
walls: string[]
}
}
type Walls = Building['room']['walls'] // string[]
See: Indexed access types
keyof
type Point = { x: number; y: number }
type P = keyof Point // 'x' | 'y'
See: keyof type operator
typeof
const user = { name: 'Ada', age: 36 }
type User = typeof user
// { name: string; age: number }
See: typeof type operator
Conditional types
type ToArray<T> = T extends unknown ? T[] : never
type StrOrNum = ToArray<string | number>
// string[] | number[]
See: Conditional types
infer
type GetReturn<T> = T extends (...args: unknown[]) => infer R
? R
: never
type Num = GetReturn<() => number> // number
type First<T extends unknown[]> =
T extends [infer F, ...unknown[]] ? F : never
type Str = First<['hello', 1]> // 'hello'
Template literal types
type Space = ' ' | '\n' | '\t'
type TrimLeft<S extends string> =
S extends `${Space}${infer Rest}` ? TrimLeft<Rest> : S
type Trimmed = TrimLeft<' hello'> // 'hello'
Functions
Function types
interface User { name: string }
function getUser(cb: (user: User) => void) {
cb({ name: 'Ada' })
}
getUser(user => console.log(user.name))
See: Function types
this parameters
function object(
this: { a: number; b: number },
a: number,
b: number
) {
this.a = a
this.b = b
return this
}
const result = object.call({ a: 0, b: 0 }, 1, 2)
// result: { a: number; b: number }
See: Declaring this
Type predicates
function isString(x: unknown): x is string {
return typeof x === 'string'
}
if (isString(value)) {
value.toUpperCase()
}
const mixed = [1, 'a', 2]
const nums = mixed.filter(x => typeof x === 'number')
// number[] (inferred predicate, 5.5)
See: Narrowing
Classes
Fields
class Point {
x: number
y: number
static instances = 0
constructor(x: number, y: number) {
this.x = x
this.y = y
Point.instances++
}
}
See: Classes
Inheritance
class Point3D extends Point {
z: number
constructor(x: number, y: number, z: number) {
super(x, y)
this.z = z
}
}
interface Colored { color: string }
class Pixel extends Point3D implements Colored {
color = '#000'
}
See: Classes
Parameter properties
class Point {
constructor(
public x: number,
public y: number,
) {}
}
Not erasable syntax; see erasable syntax.
See: Parameter properties
Definite assignment
class Point {
// assigned outside the constructor, e.g. in init()
value!: number
}
Decorators
function logged(
value: unknown,
context: ClassMethodDecoratorContext
) {
console.log(`decorating ${String(context.name)}`)
}
class Greeter {
@logged greet() {
return 'hi'
}
}
See: Decorators
Generics
Generic classes
class Greeter<T> {
greeting: T
constructor(message: T) {
this.greeting = message
}
}
const greeter = new Greeter<string>('Hello')
See: Generics
Constraints
function pluck<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const name = pluck({ name: 'Ada' }, 'name') // string
See: Generic constraints
Const type parameters
declare function tuple<const T extends readonly unknown[]>(
xs: T,
): T
const t = tuple([1, 'a'])
// readonly [1, 'a']
Modules
Exports
export const pi = 3.14
export default class Circle {}
export type { User } from './user'
export type * from './types'
See: Modules
Type-only imports
import type { User } from './user'
import { createUser, type NewUser } from './user'
verbatimModuleSyntax keeps these imports as written.
See: Type-only imports
Compiler options
| Option | Use |
|---|---|
module: "nodenext" | Node ESM and CJS resolution |
module: "bundler" | Bundler-style resolution |
module: "node20" | Node 20+ import attributes |
verbatimModuleSyntax | Keep imports as written |
erasableSyntaxOnly | Ban enums, namespaces, parameter properties |
isolatedDeclarations | Require explicit types on exports |
rewriteRelativeImportExtensions | Rewrite .ts paths to .js |
target: es2025 is the 7.0 default; ES5 support was removed.
See: TSConfig reference
Recent additions
satisfies
type Palette = Record<string, string | number[]>
const palette = {
red: [255, 0, 0],
green: '#00ff00',
} satisfies Palette
palette.red // number[]
palette.green // string
See: satisfies
Resource management
class Resource {
[Symbol.dispose]() {
console.log('closed')
}
}
{
using file = new Resource()
} // logs "closed" at block exit
using and await using dispose resources at scope exit; add esnext.disposable to lib.
See: using declarations
Erasable syntax
| Syntax | Erasable? |
|---|---|
interface, type, as | yes |
enum, namespace | no |
| Parameter properties | no |
import x = require('x') | no |
--erasableSyntaxOnly rejects non-erasable syntax so Node can strip types without a transpiler.
See: erasableSyntaxOnly
Utility types
Object types
| Utility | Meaning |
|---|---|
Partial<T> | All properties optional |
Required<T> | All properties required |
Readonly<T> | All properties readonly |
Pick<T, K> | Only keys K |
Omit<T, K> | All keys except K |
Record<K, V> | Object with keys K |
See: Utility types
Union and function types
| Utility | Meaning |
|---|---|
Exclude<T, U> | Union members not in U |
Extract<T, U> | Union members in U |
NonNullable<T> | Remove null and undefined |
ReturnType<F> | Function return type |
Parameters<F> | Function parameter tuple |
Awaited<T> | Unwrap a promise |
Uppercase<S> | Uppercase string literal |
See: Utility types
0 Comments for this cheatsheet. Write yours!