# TypeScript Cheat Sheet: Types, Generics and tsconfig

Source: https://srvscripts.com/guides/typescript-cheat-sheet/
Updated: 2026-10-09
Publisher: srvScripts (https://srvscripts.com/)

**Short answer:** TypeScript adds static types to JavaScript: annotate with `let port: number`, describe objects with `interface` or `type`, combine types with unions (`|`) and narrow them with `typeof` or a `kind` field. Generics (`<T>`) and utility types such as `Partial`, `Pick` and `Record` remove repetition. The current release is TypeScript 7.0, a native compiler that is about ten times faster and uses `strict` by default.

The examples in this TypeScript cheat sheet were type-checked with TypeScript 7.0.2 (`strict` on) and the output run with Node.js 24.21.0 on 9 October 2026. Lines marked as errors were confirmed with `// @ts-expect-error`.

## Basic types and annotations

| Syntax | What it means |
| --- | --- |
| let host: string = "web01" | Explicit annotation |
| let port = 443 | Inferred as number; annotate only where inference is not enough |
| const ids: number[] = [1, 2] · Array | Arrays, two equivalent spellings |
| const pair: [string, number] = ["db01", 3306] | Tuple: fixed length and position types |
| let maybe: string | undefined | Union: either type |
| unknown | Any value, but you must narrow it before use. Prefer it to any |
| any | Turns type checking off for that value |
| void | Function returns nothing useful |
| never | Never returns (always throws), or an impossible case |
| value as Server | Type assertion: you tell the compiler, it does not check at run time |
| value! | Non-null assertion: removes null and undefined. Use sparingly |

```
let port = 443;
port = "80";        // error TS2322: Type 'string' is not assignable to type 'number'.
```

## Interfaces and type aliases

```
interface Server {
  readonly id: number;        // cannot be reassigned
  name: string;
  ip: string;
  port?: number;              // optional: number | undefined
}

interface WebServer extends Server {
  vhosts: number;
}

type Status = "up" | "down" | "maint";         // literal union
type Point = { x: number; y: number };
type Tagged = Server & { tags: string[] };      // intersection
```

Both describe object shapes. Use `interface` for objects you may extend or merge, and `type` for unions, tuples, function types and computed types. A `readonly` property only stops reassignment through that type; it does not freeze the object.

## Unions and narrowing

| Pattern | Example |
| --- | --- |
| typeof check | if (typeof v === "number") return v.toFixed(1); |
| in check | if ("ip" in x) { ... } |
| instanceof | if (e instanceof Error) console.error(e.message); |
| Truthiness and ?. · ?? | const len = maybe?.length ?? 0; |
| Discriminated union | type Result = { ok: true; value: number } | { ok: false; error: string } |
| Type guard function | function isServer(x: unknown): x is Server { ... } |

A shared literal property (`kind` below) lets the compiler narrow each case, and the `never` assignment fails to compile if someone adds a new shape without handling it:

```
type Shape = { kind: "circle"; r: number } | { kind: "square"; side: number };

function area(s: Shape): number {
  switch (s.kind) {
    case "circle": return Math.PI * s.r ** 2;
    case "square": return s.side ** 2;
    default: {
      const _exhaustive: never = s;
      return _exhaustive;
    }
  }
}
```

## Functions and generics

| Syntax | What it does |
| --- | --- |
| function connect(host: string, port = 22, ...opts: string[]): string | Typed parameters, default, rest and return type |
| const add = (a: number, b: number): number => a + b | Typed arrow function |
| type Handler = (event: string) => void | Function type |
| function first(items: T[]): T | undefined | Generic: the type flows from the argument |
|  | Constraint: T must have a length |
| (obj: T, key: K): T[K] | Typed property access; a wrong key is a compile error |
| function parse(v: string): number; function parse(v: number): string; | Overload signatures, followed by one implementation |
| async function getJson(url: string): Promise | Async functions return Promise |

## Classes

```
abstract class Base {
  protected abstract kind: string;
  describe(): string { return `I am ${this.kind}`; }
}

class Db extends Base {
  protected kind = "db";
  #password = "x";                       // JavaScript private field (enforced at run time)
  static count = 0;

  constructor(public readonly name: string, private port: number = 3306) {
    super();                             // parameter properties create this.name and this.port
    Db.count++;
  }

  get dsn(): string { return `${this.name}:${this.port}`; }
  override describe(): string { return super.describe() + " " + this.dsn; }
}
```

`private` and `protected` are checked only at compile time; `#field` is private at run time too. Parameter properties (`public name` in the constructor) are not erasable syntax, so Node.js cannot run them directly from a `.ts` file (see the last section).

## Utility types

| Type | Result |
| --- | --- |
| Partial | Every property optional (good for PATCH payloads) |
| Required | Every property required |
| Readonly | Every property readonly |
| Pick | Only those properties |
| Omit | All except those properties |
| Record | Object with exactly those keys |
| Exclude · Extract | Remove from · keep from a union |
| NonNullable | Drop null and undefined |
| ReturnType · Parameters | Return type · parameter tuple of a function |
| Awaited | The resolved type: number |

## keyof, typeof, mapped and conditional types

| Syntax | What it does |
| --- | --- |
| const d = { host: "localhost", port: 3306 } as const | Literal, readonly types for the whole object |
| typeof d · keyof typeof d | Type of a value · its keys as a union ("host" | "port") |
| Server["ip"] | Indexed access: the type of one property |
| (typeof levels)[number] | Union of an as const array’s items |
| { [K in keyof T]: T[K] | null } | Mapped type: transform every property |
| T extends string ? "yes" : "no" | Conditional type |
| T extends (infer U)[] ? U : never | infer: extract a type from inside another |
| `${"dev" | "prod"}-${"eu" | "us"}` | Template literal type: four allowed strings |
| obj satisfies Record | Check against a type but keep the narrower inferred type |

## tsconfig and the compiler

| Command or option | What it does |
| --- | --- |
| npm install -D typescript | Installs TypeScript 7 (the native, Go-based compiler) in the project |
| npx tsc --init | Write a starter tsconfig.json |
| npx tsc · npx tsc --noEmit · npx tsc -w | Build · type-check only · watch |
| "strict": true | All strict checks. Default since TypeScript 6.0 |
| "noUncheckedIndexedAccess": true | rec[key] becomes T | undefined |
| "module": "nodenext" | Correct ESM and CommonJS rules for Node.js |
| "rootDir": "./src" · "outDir": "./dist" | Input and output folders. Set rootDir explicitly in 7.0 |
| "types": ["node"] | Global type packages. The default is now [], so list the ones you need |
| "erasableSyntaxOnly": true | Reject enums, namespaces and parameter properties |
| --checkers 2 · --singleThreaded | Control parallel type-checking (TypeScript 7) |

TypeScript 7 adopts the 6.0 defaults and turns 6.0 deprecations into errors: `target: es5`, `baseUrl`, `moduleResolution: node` and the AMD, UMD and SystemJS module formats are gone. Tools that still need the old compiler API, such as typescript-eslint, can use the `@typescript/typescript6` package side by side.

## For server admins: config files and running .ts in Node.js

JSON from a file or an API is `unknown` until you check it. Validate the fields you need instead of casting blindly:

```
interface AppConfig { host: string; port: number; replicas?: string[] }

function loadConfig(text: string): AppConfig {
  const data: unknown = JSON.parse(text);
  if (typeof data !== "object" || data === null) throw new Error("config must be an object");
  const { host, port } = data as Record;
  if (typeof host !== "string" || typeof port !== "number") {
    throw new Error("host and port are required");
  }
  return data as AppConfig;
}
```

Node.js 24 runs a `.ts` file directly (`node check.ts`) by stripping the types, without type-checking. It accepts only erasable syntax: an `enum` or a constructor parameter property makes it fail with a syntax error. Run `npx tsc --noEmit` in CI for the type check, and set `erasableSyntaxOnly` so the editor flags code that Node.js cannot strip. For large scripts, compile with `tsc` and run the JavaScript in `dist/`.

**Official documentation (checked 9 October 2026):** [The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) · [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html) · [TSConfig Reference](https://www.typescriptlang.org/tsconfig/) · [Announcing TypeScript 7.0](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/) · [Node.js v24: Modules: TypeScript](https://nodejs.org/docs/latest-v24.x/api/typescript.html)

## TypeScript Cheat Sheet at a glance

In short: A compact TypeScript 7.0 reference covering types, narrowing, generics, utility types and tsconfig, with examples checked by tsc 7.0.2.

TypeScript Cheat Sheet: what this guide covers.

**Related:** [JavaScript Cheat Sheet: Modern Syntax for Browser and Node](https://srvscripts.com/guides/javascript-cheat-sheet/) · [JSON Formatter and Validator](https://srvscripts.com/tools/json-formatter/) · [Regex Tester for JavaScript](https://srvscripts.com/tools/regex-tester/).
