npm i -D typescriptInstall the compiler as a dev dependency.npx tsc --initScaffold a starter tsconfig.json.tsc★Type-check and emit .js beside your .ts.tsc --noEmit★Type-check only — no output. Ideal in CI.tsc -wWatch mode — re-check on save.tsc -p tsconfig.jsonCheck against a specific config file.tsc -bBuild mode — honours project references.// @ts-checkOpt a plain .js file INTO type-checking.// @ts-expect-error★Assert the next line errors (fails if it doesn't).// @ts-ignoreSilence the next line (prefer @ts-expect-error).// @ts-nocheckTurn OFF checking for a whole file.
let s: string = "hi"★Annotate a variable after its name.let n = 42★Inference — n is number, no annotation needed.const c = "hi"const infers the literal type "hi", not string.let ok: booleanstring · number · boolean · bigint · symbol.let a: anyavoidOpts OUT of checking — contagious.let u: unknown★Safe any — must narrow before use.let e: null | undefinedThe two empty types (distinct under strict).function log(): void {}void = returns nothing useful.const die = (): never => { throw 0 }never = never returns (throws / loops).let id: string | number★Union — one value, several allowed types.
let xs: number[]★Array of numbers (also Array). let ro: readonly string[]Immutable array — no push / splice.let pair: [string, number]★Tuple — fixed length & positions.let p: [x: number, y: number]Named tuple elements (labels only).let opt: [number, number?]Optional trailing tuple element.let t: [string, ...number[]]Tuple with a variadic tail.let o: { name: string; age?: number }★Inline object type; age? is optional.let m: { readonly id: number }readonly property — set once.let d: { [key: string]: number }Index signature — arbitrary keys.
type Dir = "n" | "s" | "e" | "w"★Literal union — the idiomatic enum.let x: 0 | 1 | 2Number literal types work too.const t = [1, 2] as const★as const → readonly literal tuple.type Shape = { kind: "c"; r: number } | { kind: "s"; s: number }★Discriminated union — a shared literal tag field.enum Role { Admin, Editor }emits JSEnum — but it emits runtime code.enum Dir2 { Up = "UP", Down = "DOWN" }emits JSString enum — readable emitted values.const enum Flag { On, Off }const enum → inlined, zero output.type In = string | number | nullModel several input shapes in one type.
interface User { id: number; name: string }★Interface — the go-to for object shapes.type Point = { x: number; y: number }★type — names ANY type, not just objects.interface Admin extends User { role: string }★Inherit members, then add more.interface C extends A, B {}Extend several interfaces at once.type Both = A & BIntersection — must satisfy BOTH.interface Box<T> { value: T }Generic interface — parameterised shape.interface Fn { (u: string): void }Call signature — a callable type.interface Ctor { new (s: string): User }Construct signature — a newable type.// declare interface Box twice -> mergedDeclaration merging — same-name interfaces combine.type Id = string // vs interfaceUse type for unions / tuples / mapped types.
if (typeof x === "string") {}★typeof guard — narrows primitives.if (x instanceof Date) {}instanceof — narrows class instances.if ("role" in obj) {}★in — narrows by property presence.if (x) { /* truthy */ }Removes null / undefined / 0 / '' from the type.if (a != null) {}★!= null drops BOTH null and undefined.if (Array.isArray(x)) {}Built-in guard — narrows to an array.x?.prop ?? fallbackOptional chaining + nullish default (ES2020+).switch (s.kind) { }★Discriminated union — switch on a tag field.function isCat(a: Animal): a is CatType predicate — your own guard.function assert(c: unknown): asserts cAssertion function — narrows after it runs.const _: never = s // exhaustivenever check errors if a case is missed.
function add(a: number, b: number): number★Param types + return type.const f = (x: number): string => `${x}`★Typed arrow function.function g(a: number, b?: number) {}★b? optional → number | undefined.function h(a: number, b = 10) {}Default param — type inferred from default.function sum(...ns: number[]): numberRest params typed as an array.function map(a: T[], f: (x: T) => T): T[]Callback typed inline as a parameter.function pt({ x, y }: Point) {}Destructured params keep the object type.type Handler = (e: Event) => voidName a function type with type.function on(e: "click", cb: () => void): voidOverload signatures for varied calls.function each(this: Widget, i: number) {}Typed this parameter (erased at runtime).
function id<T>(x: T): T { return x }★Generic fn — T flows in and out.function first<T>(a: T[]): TT is inferred from the argument.function get<T, K extends keyof T>(o: T, k: K): T[K]★Return the type at key K — the canonical constraint.<T extends object>★Constraint — T must fit object.function make<T = string>() {}Default type parameter.function tup<const T>(t: T): Tconst type param — infers narrow literals.class Box<T> { constructor(public v: T) {} }Generic class.
class P { x: number = 0 }Field with type + initializer.constructor(public x: number) {}★Parameter property — declares & assigns x.private secret = 1★public · private · protected access.protected kind = 0protected — visible to subclasses only.readonly id: numberAssignable only in the constructor.static count = 0Belongs to the class, not instances.static { count = load() }Static init block (ES2022).abstract class Shape { abstract area(): number }Can't instantiate; subclasses implement.class Dog extends Animal { override speak() {} }override — checked against the base method.class Dog implements Animal {}★implements — shape-checked at compile time.#real = 42True JS-private field (runtime, not erased).get name(): string { return this._n }Accessors — typed get / set.
@sealed class C {}Class decorator — receives the class.@log run() {}Method decorator — wraps the method.function log(fn, ctx: ClassMethodDecoratorContext)Standard (TC39) decorator signature.ctx.kind 路 ctx.name 路 ctx.addInitializer()The context tells you what's being decorated.function bind(label: string) { return dec }Decorator factory — takes args, returns a decorator.accessor x = 0Auto-accessor field — decoratable.// experimentalDecorators = legacyPre-standard decorators need that flag + reflect-metadata.
type K = keyof User★Union of keys: "id" | "name".type T = typeof myConst★Lift a VALUE into its type.type V = User["name"]★Indexed access — the type at a key.type E = Arr[number]Element type of an array / tuple type.type Item = typeof list[number]Element type of a value array (typeof + [number]).type Vals = User[keyof User]Union of all property value types.
type Opt<T> = { [K in keyof T]?: T[K] }★Walk every key — here make all optional.{ readonly [K in keyof T]: T[K] }Add readonly to each key.{ -readonly [K in keyof T]-?: T[K] }Strip modifiers with -readonly / -?.{ [K in keyof T as `get${K & string}`]: T[K] }Key remapping with as (rename keys).{ [K in keyof T as T[K] extends Fn ? K : never]: T[K] }Remap to never to FILTER keys out.type R = { [K in "a" | "b"]: number }Map over a literal union directly.
type NN<T> = T extends null ? never : T★T extends U ? X : Y — a type-level if.type El<T> = T extends (infer U)[] ? U : T★infer captures a type inside the match.type ToArr<T> = T extends any ? T[] : neverA naked T distributes over each union member.type Ret<F> = F extends () => infer V ? V : neverPull a function's return type out.T extends `${infer C extends string}${string}`Constrain what infer may capture.type Greet = `hello ${string}`★Template literal type.type Ev = `on${Capitalize<Key>}`Compose with Uppercase / Capitalize.// `${infer H}${infer T}` on "馃榾abc"TS 7TS 7: template inference keeps Unicode points.
Partial<T>★All properties optional.Required<T>All properties required.Readonly<T>All properties readonly.Pick<T, K>★Keep only keys K.Omit<T, K>★Drop keys K.Record<K, V>★Object type with keys K, values V.Exclude<U, M> 路 Extract<U, M>Remove / keep members of a union.NonNullable<T>Remove null and undefined.ReturnType<F> 路 Parameters<F>★A function's return / params tuple.InstanceType<C> 路 ConstructorParameters<C>A class's instance / constructor args.Awaited<T>Unwrap a Promise's resolved type.NoInfer<T>Block inference at this position (TS 5.4+).Uppercase<S> 路 Capitalize<S>Intrinsic string-literal transforms.
el as HTMLInputElement★as — trust me, it's this type (unchecked).value satisfies Config★Check against a type WITHOUT widening it.routes as constFreeze to the narrowest literal type.el!.focus()★Non-null assertion — 'not null here'.let x!: numberDefinite assignment — 'set before use'.<Foo>bar // .ts only, clashes with JSXAngle-bracket assertion (avoid in .tsx).x as unknown as TavoidDouble assertion to force unrelated types.
export type { User }★Export a type explicitly.import type { User } from "./u"★Type-only import — erased from JS.import { type T, val } from './m'Inline type modifier — mix types & values.declare const VERSION: stringAmbient declaration — 'exists elsewhere'.declare module "*.svg" { const s: string }Type a non-code import.// types.d.tsDeclaration file — types, no implementation./// <reference types="node" />Triple-slash directive — pull in ambient types.declare global { interface Window {} }Augment global / third-party types.
Promise<string>★Async result type.Array<T> 路 ReadonlyArray<T>Generic array forms.Map<K, V> 路 Set<T>Typed collections.Record<string, unknown>Safe shape for parsed JSON.Iterable<T> 路 Iterator<T>Anything you can for…of.() => void★Function type literal.Record<string, number>Quick dictionary type.Set<T>.union 路 RegExp.escape 路 Promise.tryes2025 libWithtarget: es2025the lib types cover ES2025 (Set methods, iterator helpers,Promise.try,RegExp.escape).
"strict": true★TS 7Turns on all strict checks — TS 7 default."noImplicitAny": trueError on inferred any."strictNullChecks": true★null / undefined not in every type."noUncheckedIndexedAccess": truearr[i] / obj[k] become T | undefined."target": "es2025"★TS 7JS version to emit — TS 7 defaults to the latest stable ES (es2025); es5/es3 are gone."module": "esnext"TS 7Module output — TS 7 default."moduleResolution": "bundler"TS 7How imports resolve (node10 gone in 7)."verbatimModuleSyntax": trueEmit imports as written — forces import type."declaration": trueEmit .d.ts files alongside .js."skipLibCheck": trueSkip checking .d.ts files (faster)."paths": { "@/*": ["src/*"] }Import path aliases.
node app.ts★Node 22.18+ / 24+ strips types and runs it — no build.node --experimental-transform-types a.tsEnums & namespaces emit code — need this mode.npx tsx app.ts★tsx (or ts-node) runs TS on any Node, incl. old LTS.deno run app.ts 路 bun app.tsDeno & Bun execute TS natively, enums included.tsc --noEmit★Runtimes DON'T type-check — keep tsc as the gate."erasableSyntaxOnly": trueBan enum / namespace / param-props — strip-safe.tsc -bBuild mode — incremental project references (monorepos)."isolatedDeclarations": trueEmit .d.ts fast, without whole-program checking (5.5+).
const cfg = { port: 8080 } satisfies Config★Typed config that keeps its literal types.type UserId = string & { readonly _b: 'UserId' }Branded type — a UserId isn't just any string.type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }Recursive optional — patch nested objects.Object.keys(o) as (keyof typeof o)[]Object.keys returns string[] — assert to keys.function assertNever(x: never): never★Call in a default case to force exhaustiveness.(await res.json()) as UserJSON crosses in as unknown — assert or validate.type Prettify<T> = { [K in keyof T]: T[K] } & {}Flatten an intersection into a clean hover type.