Reference Topics

These handbook reference topics appear in existing code more often than in new code. Four generate JavaScript (enums, decorators, namespaces, JSX) and deserve a closer look below; the rest fit in a table.

Reference topics at a glance
Topic What TypeScript adds Example
Symbols unique symbol type for const or static readonly const ID: unique symbol = Symbol()
Iterators Iterable<T> and Generator<T, TReturn, TNext> function* ids(): Generator<number>
Mixins A constructor type for class factories (Mixins) type Ctor = new (...a: any[]) => {}
Triple-slash directives File-top comments naming dependencies /// <reference types="node" />
Type compatibility Structural: same shape, same type A Dog class fits a Pet interface
Type inference Best common type and contextual typing [0, 1, null] is (number | null)[]

Use /// <reference types> only in hand-written .d.ts files; in .ts files the types option of tsconfig.json does the job (Project Configuration). Structural compatibility has one nominal exception: classes with private or protected members are compatible only if those members come from the same declaration.

Enums versus union literals

An enum creates a runtime object. Numeric enums get a reverse mapping from value to name; string enums do not. The handbook itself says you may not need an enum when an object with as const suffices, and erasableSyntaxOnly (Installing and Running) rejects enums outright.

A numeric enum, a string enum and an as const objectCSS
enum Level { Low = 1, High }                       // numeric: reverse mapping
enum Dir { Up = "UP", Down = "DOWN" }              // string: no reverse mapping
const Status = { Active: "active", Archived: "archived" } as const;
type Status = (typeof Status)[keyof typeof Status]; // "active" | "archived"
function move(d: Dir) { return d; }
function setStatus(s: Status) { return s; }
console.log(Level.High, Level[2], move(Dir.Up), setStatus("archived"));
move("UP");
const lvl: Level = 7;
Output
enums.ts(12,6): error TS2345: Argument of type '"UP"' is not assignable to parameter of type
  'Dir'.
enums.ts(13,7): error TS2322: Type '7' is not assignable to type 'Level'.

The valid lines log 2 High UP archived, and Level compiles to Level[Level["Low"] = 1] = "Low" inside an IIFE. A string enum is nominal: even the exact string "UP" is refused, so callers must import Dir. The union type accepts a plain "archived" and costs nothing at run time. const enum inlines values but breaks under isolatedModules when it comes from a declaration file, so avoid it in libraries.

Decorators

TypeScript 5.0 implemented the standard ECMAScript decorators described in Decorators, with context types such as ClassMethodDecoratorContext that make a decorator generic over the method it wraps. The older experimentalDecorators flag remains for code written against the earlier proposal.

A type-safe standard method decoratorJavaScript
function logged<This, Args extends unknown[], R>(
  method: (this: This, ...args: Args) => R,
  context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => R>,
) {
  return function (this: This, ...args: Args): R {
    console.log(`${String(context.name)}(${args.join(", ")})`);
    return method.call(this, ...args);
  };
}
class Cart {
  @logged add(price: number, qty: number) { return price * qty; }
}
console.log(new Cart().add(4, 3));
Output
add(4, 3)
12

Put @logged on a field instead and tsc reports TS1240, "Unable to resolve signature of property decorator when called as an expression". The emitted file contains an __esDecorate helper, because no runtime supports the syntax yet. Standard decorators cannot decorate parameters and do not work with emitDecoratorMetadata, so the NestJS starter project still sets experimentalDecorators and emitDecoratorMetadata. Lit supports both styles.

Declaration merging and namespaces

When two declarations share a name, TypeScript merges them. Interfaces merge member by member, which is how you add properties to library types with declare global or declare module "pkg". A namespace can merge into a function, class or enum to attach static members; classes never merge with classes.

Interface merging, global augmentation and a function-namespace mergeShell
export {};                                         // make this file a module
interface Box { width: number }
interface Box { height: number }                   // merged: { width; height }
const box: Box = { width: 2, height: 3 };
declare global {
  interface Window { appVersion: string }          // augment a lib.dom.d.ts type
}
function money(n: number) { return `$${n.toFixed(2)}`; }
namespace money {                                  // function + namespace merge
  export const currency = "USD";
}
console.log(box.width * box.height, money(4), money.currency);
Output
6 $4.00 USD

Two classes named Box would fail with TS2300, "Duplicate identifier". The namespace compiles to an IIFE that assigns money.currency, which is why erasableSyntaxOnly rejects it with TS1294. Namespaces predate ES modules; in new code use modules (Modules) and keep declare namespace for describing globals in .d.ts files (Declaration Files). TypeScript 6.0 deprecated the old spelling module Foo {}.

JSX

Files ending in .tsx may contain JSX, which TypeScript type-checks against JSX.IntrinsicElements from the library's types (install @types/react for React 7,897 ). The jsx option picks the output: preserve leaves JSX in a .jsx file for a bundler, react emits React.createElement calls, and react-jsx emits the automatic runtime, so <span className="badge">{n}</span> becomes _jsx("span", { className: "badge", children: n }) with import { jsx as _jsx } from "react/jsx-runtime". Set jsxImportSource to preact to import preact/jsx-runtime instead.