Syntax#

TypeScript starts from JavaScript syntax and layers type annotations on top: a colon after a binding or parameter, an optional return type after a function signature, as for assertions, ! for non-null, ? for optional members. Everything else (statements, expressions, literals, operators, control flow) is JavaScript; see Syntax for the base layer.

/types`.

Annotations#

The basic annotation form is name: Type.

const count: number = 0;
let name: string = "rk";
const items: string[] = [];
const config: {host: string; port: number} = {host: "0.0.0.0", port: 80};

function add(a: number, b: number): number {
  return a + b;
}

const greet = (name: string): string => `hello, ${name}`;

Annotations are optional whenever the compiler can infer the type. The operator leaves inference do its job for locals; annotates exports, public function signatures, and any binding whose inferred type would be wider than intended.

const xs = [1, 2, 3];                    // inferred: number[]
const config = {host: "0.0.0.0"};        // inferred: {host: string}

Assertions#

x as T tells the compiler to treat x as T without checking. Use this only when the compiler genuinely cannot follow the proof; otherwise the type system loses its guarantees.

const el = document.getElementById("root") as HTMLDivElement;

const data = JSON.parse(raw) as Config;      // dangerous; use zod instead

The older <T>x syntax exists but conflicts with JSX; the operator writes as form by default.

The non-null assertion ! is a special case: x! is x as NonNullable<typeof x>. Useful after a runtime check the compiler does not see.

const found = items.find(x => x.id === id);
process(found!);             // operator knows it exists

const assertion (as const) narrows literal types and makes everything readonly.

const tuple = [1, 2, 3] as const;            // readonly [1, 2, 3]
const colors = ["red", "green", "blue"] as const;
//  ^? readonly ["red", "green", "blue"]
type Color = (typeof colors)[number];        // "red" | "green" | "blue"

The satisfies operator (x satisfies T) checks that x conforms to T without widening the type. Preferred over a plain annotation when you want the inferred narrow type and the conformance check.

const handlers = {
  get:  (req) => req.path,
  post: (req) => req.body,
} satisfies Record<string, (req: Req) => unknown>;

handlers.get;        // type is (req: Req) => string, not the wider Record value

Optional and readonly#

? marks an object property or parameter as optional; readonly marks it immutable.

interface Config {
  readonly host: string;       // cannot reassign
  port?: number;               // optional
}

function listen(opts: {host: string; port?: number}) { /* … */ }
listen({host: "0.0.0.0"});     // port omitted

Declarations#

declare introduces an ambient identifier with no implementation; use it inside .d.ts files to describe a JavaScript module.

declare const __VERSION__: string;          // injected by bundler
declare module "legacy-lib" {
  export function compute(x: number): number;
}

type declares a type alias; interface declares an object or function structure. Both are erased at runtime; see Types for when to pick which.

type ID = string | number;
interface User { id: ID; name: string; }

Comments#

JavaScript comments work identically. // @ts-ignore and // @ts-expect-error suppress a single line of type errors; @ts-expect-error is preferred because it fails when the error goes away (telling the operator the suppression is now stale).

// @ts-expect-error: third-party types are wrong, fixed in v3
thirdParty.brokenCall();

/** */ JSDoc blocks are read by the compiler; useful in plain .js files run through TypeScript with allowJs plus checkJs.

Type-only imports#

import type and export type carry only type information; they are erased at compile time and never trigger a runtime import.

import type {Config}   from "./config.js";   // erased
import {load}          from "./loader.js";   // runtime import

For projects with isolatedModules: true (Vite, esbuild, swc), write import type consistently.

References#