typescript-expert

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

TypeScript Expert

TypeScript 专家

Глубокая экспертиза в системе типов TypeScript, продвинутых паттернах и best practices.
精通TypeScript类型系统、高级模式及最佳实践。

Core Principles

核心原则

Foundational Guidelines

基础准则

yaml
typescript_principles:
  - name: "Type Safety Priority"
    guideline: "Always prefer strict type checking and avoid `any` type"
    reason: "Catch errors at compile time, not runtime"

  - name: "Smart Inference"
    guideline: "Let TypeScript infer types when they're obvious"
    reason: "Reduce noise while maintaining safety"

  - name: "Immutability Preference"
    guideline: "Use readonly and as const for unchangeable data"
    reason: "Prevent accidental mutations"

  - name: "Discriminated Unions"
    guideline: "Apply tagged unions for managing complex state"
    reason: "Exhaustive type checking and better DX"

  - name: "Explicit Public APIs"
    guideline: "Always type public function signatures explicitly"
    reason: "Documentation and contract enforcement"

yaml
typescript_principles:
  - name: "Type Safety Priority"
    guideline: "Always prefer strict type checking and avoid `any` type"
    reason: "Catch errors at compile time, not runtime"

  - name: "Smart Inference"
    guideline: "Let TypeScript infer types when they're obvious"
    reason: "Reduce noise while maintaining safety"

  - name: "Immutability Preference"
    guideline: "Use readonly and as const for unchangeable data"
    reason: "Prevent accidental mutations"

  - name: "Discriminated Unions"
    guideline: "Apply tagged unions for managing complex state"
    reason: "Exhaustive type checking and better DX"

  - name: "Explicit Public APIs"
    guideline: "Always type public function signatures explicitly"
    reason: "Documentation and contract enforcement"

Type System Fundamentals

类型系统基础

Basic Types

基础类型

typescript
// Primitive types
const name: string = "John";
const age: number = 30;
const isActive: boolean = true;
const nothing: null = null;
const notDefined: undefined = undefined;
const unique: symbol = Symbol("id");
const bigNumber: bigint = 9007199254740991n;

// Arrays
const numbers: number[] = [1, 2, 3];
const strings: Array<string> = ["a", "b", "c"];
const readonly: readonly number[] = [1, 2, 3]; // immutable

// Tuples
const tuple: [string, number] = ["age", 30];
const namedTuple: [name: string, age: number] = ["John", 30];
const optionalTuple: [string, number?] = ["John"];
const restTuple: [string, ...number[]] = ["sum", 1, 2, 3];

// Objects
const user: { name: string; age: number } = { name: "John", age: 30 };
const optionalProps: { name: string; age?: number } = { name: "John" };
const readonlyObj: Readonly<{ name: string }> = { name: "John" };
typescript
// 原始类型
const name: string = "John";
const age: number = 30;
const isActive: boolean = true;
const nothing: null = null;
const notDefined: undefined = undefined;
const unique: symbol = Symbol("id");
const bigNumber: bigint = 9007199254740991n;

// 数组
const numbers: number[] = [1, 2, 3];
const strings: Array<string> = ["a", "b", "c"];
const readonly: readonly number[] = [1, 2, 3]; // 不可变

// 元组
const tuple: [string, number] = ["age", 30];
const namedTuple: [name: string, age: number] = ["John", 30];
const optionalTuple: [string, number?] = ["John"];
const restTuple: [string, ...number[]] = ["sum", 1, 2, 3];

// 对象
const user: { name: string; age: number } = { name: "John", age: 30 };
const optionalProps: { name: string; age?: number } = { name: "John" };
const readonlyObj: Readonly<{ name: string }> = { name: "John" };

Union and Intersection Types

联合类型与交叉类型

typescript
// Union types (OR)
type Status = "pending" | "active" | "completed";
type StringOrNumber = string | number;

// Intersection types (AND)
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged; // { name: string; age: number }

// Discriminated unions (tagged unions)
type Result<T, E = Error> =
  | { success: true; data: T }
  | { success: false; error: E };

function handleResult<T>(result: Result<T>): T | null {
  if (result.success) {
    return result.data; // TypeScript knows data exists
  }
  console.error(result.error); // TypeScript knows error exists
  return null;
}

// Exhaustive checking
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "rectangle"; width: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.side ** 2;
    case "rectangle":
      return shape.width * shape.height;
    default:
      // Exhaustive check - compiler error if case is missing
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

typescript
// 联合类型(或)
type Status = "pending" | "active" | "completed";
type StringOrNumber = string | number;

// 交叉类型(与)
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged; // { name: string; age: number }

// 可区分联合类型(标记联合)
type Result<T, E = Error> =
  | { success: true; data: T }
  | { success: false; error: E };

function handleResult<T>(result: Result<T>): T | null {
  if (result.success) {
    return result.data; // TypeScript 知道data存在
  }
  console.error(result.error); // TypeScript 知道error存在
  return null;
}

// 穷尽检查
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; side: number }
  | { kind: "rectangle"; width: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.side ** 2;
    case "rectangle":
      return shape.width * shape.height;
    default:
      // 穷尽检查 - 如果缺少case会触发编译器错误
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

Advanced Type System

高级类型系统

Generics

泛型

typescript
// Basic generics
function identity<T>(value: T): T {
  return value;
}

// Multiple type parameters
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second];
}

// Generic constraints
interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(item: T): T {
  console.log(item.length);
  return item;
}

// Generic with default type
interface Container<T = string> {
  value: T;
}

// Constrained generics
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// Generic classes
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }
}

// Generic with multiple constraints
function merge<T extends object, U extends object>(a: T, b: U): T & U {
  return { ...a, ...b };
}
typescript
// 基础泛型
function identity<T>(value: T): T {
  return value;
}

// 多类型参数
function pair<T, U>(first: T, second: U): [T, U] {
  return [first, second];
}

// 泛型约束
interface Lengthwise {
  length: number;
}

function logLength<T extends Lengthwise>(item: T): T {
  console.log(item.length);
  return item;
}

// 带默认类型的泛型
interface Container<T = string> {
  value: T;
}

// 约束泛型
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// 泛型类
class Stack<T> {
  private items: T[] = [];

  push(item: T): void {
    this.items.push(item);
  }

  pop(): T | undefined {
    return this.items.pop();
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1];
  }
}

// 多约束泛型
function merge<T extends object, U extends object>(a: T, b: U): T & U {
  return { ...a, ...b };
}

Utility Types

工具类型

typescript
// Built-in utility types
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// Partial - all properties optional
type PartialUser = Partial<User>;

// Required - all properties required
type RequiredUser = Required<PartialUser>;

// Readonly - all properties readonly
type ReadonlyUser = Readonly<User>;

// Pick - select specific properties
type UserCredentials = Pick<User, "email" | "password">;

// Omit - exclude specific properties
type PublicUser = Omit<User, "password">;

// Record - create object type with specific keys
type UserRoles = Record<string, "admin" | "user" | "guest">;

// Exclude - exclude types from union
type NonNullableString = Exclude<string | null | undefined, null | undefined>;

// Extract - extract types from union
type StringsOnly = Extract<string | number | boolean, string>;

// NonNullable - remove null and undefined
type NonNullUser = NonNullable<User | null | undefined>;

// ReturnType - get function return type
function createUser() {
  return { id: 1, name: "John" };
}
type UserReturn = ReturnType<typeof createUser>;

// Parameters - get function parameters as tuple
type CreateUserParams = Parameters<typeof createUser>;

// ConstructorParameters - get constructor parameters
class UserClass {
  constructor(public name: string, public age: number) {}
}
type UserConstructorParams = ConstructorParameters<typeof UserClass>;

// InstanceType - get instance type from constructor
type UserInstance = InstanceType<typeof UserClass>;

// Awaited - unwrap Promise type
type ResolvedUser = Awaited<Promise<User>>;
typescript
// 内置工具类型
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// Partial - 所有属性可选
type PartialUser = Partial<User>;

// Required - 所有属性必填
type RequiredUser = Required<PartialUser>;

// Readonly - 所有属性只读
type ReadonlyUser = Readonly<User>;

// Pick - 选择特定属性
type UserCredentials = Pick<User, "email" | "password">;

// Omit - 排除特定属性
type PublicUser = Omit<User, "password">;

// Record - 创建带特定键的对象类型
type UserRoles = Record<string, "admin" | "user" | "guest">;

// Exclude - 从联合类型中排除类型
type NonNullableString = Exclude<string | null | undefined, null | undefined>;

// Extract - 从联合类型中提取类型
type StringsOnly = Extract<string | number | boolean, string>;

// NonNullable - 移除null和undefined
type NonNullUser = NonNullable<User | null | undefined>;

// ReturnType - 获取函数返回类型
function createUser() {
  return { id: 1, name: "John" };
}
type UserReturn = ReturnType<typeof createUser>;

// Parameters - 将函数参数转为元组
type CreateUserParams = Parameters<typeof createUser>;

// ConstructorParameters - 获取构造函数参数
class UserClass {
  constructor(public name: string, public age: number) {}
}
type UserConstructorParams = ConstructorParameters<typeof UserClass>;

// InstanceType - 从构造函数获取实例类型
type UserInstance = InstanceType<typeof UserClass>;

// Awaited - 解包Promise类型
type ResolvedUser = Awaited<Promise<User>>;

Conditional Types

条件类型

typescript
// Basic conditional type
type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

// Conditional type with infer
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type Resolved = UnwrapPromise<Promise<string>>; // string
type NotPromise = UnwrapPromise<number>; // number

// Extract return type from function
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// Extract array element type
type ArrayElement<T> = T extends (infer E)[] ? E : never;
type Element = ArrayElement<string[]>; // string

// Distributive conditional types
type ToArray<T> = T extends any ? T[] : never;
type Distributed = ToArray<string | number>; // string[] | number[]

// Non-distributive (wrap in tuple)
type ToArrayNonDistributive<T> = [T] extends [any] ? T[] : never;
type NonDistributed = ToArrayNonDistributive<string | number>; // (string | number)[]

// Practical example: Deep readonly
type DeepReadonly<T> = T extends (infer U)[]
  ? DeepReadonlyArray<U>
  : T extends object
  ? DeepReadonlyObject<T>
  : T;

interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}

type DeepReadonlyObject<T> = {
  readonly [P in keyof T]: DeepReadonly<T[P]>;
};
typescript
// 基础条件类型
type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

// 带infer的条件类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type Resolved = UnwrapPromise<Promise<string>>; // string
type NotPromise = UnwrapPromise<number>; // number

// 提取函数返回类型
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 提取数组元素类型
type ArrayElement<T> = T extends (infer E)[] ? E : never;
type Element = ArrayElement<string[]>; // string

// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;
type Distributed = ToArray<string | number>; // string[] | number[]

// 非分布式(包装为元组)
type ToArrayNonDistributive<T> = [T] extends [any] ? T[] : never;
type NonDistributed = ToArrayNonDistributive<string | number>; // (string | number)[]

// 实际示例:深度只读
type DeepReadonly<T> = T extends (infer U)[]
  ? DeepReadonlyArray<U>
  : T extends object
  ? DeepReadonlyObject<T>
  : T;

interface DeepReadonlyArray<T> extends ReadonlyArray<DeepReadonly<T>> {}

type DeepReadonlyObject<T> = {
  readonly [P in keyof T]: DeepReadonly<T[P]>;
};

Template Literal Types

模板字面量类型

typescript
// Basic template literals
type Greeting = `Hello, ${string}!`;
type ValidGreeting = "Hello, World!"; // valid
// type InvalidGreeting: "Hi, World!" // error

// Event names
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"

// CSS units
type CSSUnit = "px" | "em" | "rem" | "%";
type CSSValue = `${number}${CSSUnit}`;

const width: CSSValue = "100px"; // valid
const height: CSSValue = "50%"; // valid

// Getter/Setter patterns
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type Setters<T> = {
  [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

interface Person {
  name: string;
  age: number;
}

type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }

// Route patterns
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Route = `/${string}`;
type Endpoint = `${HTTPMethod} ${Route}`;

const endpoint: Endpoint = "GET /users"; // valid
typescript
// 基础模板字面量
type Greeting = `Hello, ${string}!`;
type ValidGreeting = "Hello, World!"; // 有效
// type InvalidGreeting: "Hi, World!" // 错误

// 事件名称
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"

// CSS单位
type CSSUnit = "px" | "em" | "rem" | "%";
type CSSValue = `${number}${CSSUnit}`;

const width: CSSValue = "100px"; // 有效
const height: CSSValue = "50%"; // 有效

// Getter/Setter模式
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type Setters<T> = {
  [K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};

interface Person {
  name: string;
  age: number;
}

type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }

// 路由模式
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Route = `/${string}`;
type Endpoint = `${HTTPMethod} ${Route}`;

const endpoint: Endpoint = "GET /users"; // 有效

Mapped Types

映射类型

typescript
// Basic mapped type
type Optional<T> = {
  [K in keyof T]?: T[K];
};

// Mapped type with modifier removal
type Concrete<T> = {
  [K in keyof T]-?: T[K]; // remove optional
};

type Mutable<T> = {
  -readonly [K in keyof T]: T[K]; // remove readonly
};

// Key remapping
type PrefixedKeys<T, P extends string> = {
  [K in keyof T as `${P}${Capitalize<string & K>}`]: T[K];
};

interface Config {
  host: string;
  port: number;
}

type PrefixedConfig = PrefixedKeys<Config, "server">;
// { serverHost: string; serverPort: number }

// Filter keys by value type
type FilterByType<T, U> = {
  [K in keyof T as T[K] extends U ? K : never]: T[K];
};

interface Mixed {
  name: string;
  age: number;
  active: boolean;
  email: string;
}

type StringProps = FilterByType<Mixed, string>;
// { name: string; email: string }

// Nullable all properties
type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

// Create event handlers
type EventHandlers<T> = {
  [K in keyof T as `on${Capitalize<string & K>}Change`]: (newValue: T[K]) => void;
};

type PersonHandlers = EventHandlers<Person>;
// { onNameChange: (newValue: string) => void; onAgeChange: (newValue: number) => void }

typescript
// 基础映射类型
type Optional<T> = {
  [K in keyof T]?: T[K];
};

// 移除修饰符的映射类型
type Concrete<T> = {
  [K in keyof T]-?: T[K]; // 移除可选修饰符
};

type Mutable<T> = {
  -readonly [K in keyof T]: T[K]; // 移除只读修饰符
};

// 键重映射
type PrefixedKeys<T, P extends string> = {
  [K in keyof T as `${P}${Capitalize<string & K>}`]: T[K];
};

interface Config {
  host: string;
  port: number;
}

type PrefixedConfig = PrefixedKeys<Config, "server">;
// { serverHost: string; serverPort: number }

// 按值类型过滤键
type FilterByType<T, U> = {
  [K in keyof T as T[K] extends U ? K : never]: T[K];
};

interface Mixed {
  name: string;
  age: number;
  active: boolean;
  email: string;
}

type StringProps = FilterByType<Mixed, string>;
// { name: string; email: string }

// 所有属性可为空
type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

// 创建事件处理器
type EventHandlers<T> = {
  [K in keyof T as `on${Capitalize<string & K>}Change`]: (newValue: T[K]) => void;
};

type PersonHandlers = EventHandlers<Person>;
// { onNameChange: (newValue: string) => void; onAgeChange: (newValue: number) => void }

Type Guards

类型守卫

Built-in Type Guards

内置类型守卫

typescript
// typeof guard
function processValue(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // TypeScript knows it's string
  }
  return value.toFixed(2); // TypeScript knows it's number
}

// instanceof guard
class Dog {
  bark() {
    console.log("Woof!");
  }
}

class Cat {
  meow() {
    console.log("Meow!");
  }
}

function speak(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}

// in operator guard
interface Fish {
  swim: () => void;
}

interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}
typescript
// typeof 守卫
function processValue(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // TypeScript 知道这是string类型
  }
  return value.toFixed(2); // TypeScript 知道这是number类型
}

// instanceof 守卫
class Dog {
  bark() {
    console.log("Woof!");
  }
}

class Cat {
  meow() {
    console.log("Meow!");
  }
}

function speak(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}

// in 操作符守卫
interface Fish {
  swim: () => void;
}

interface Bird {
  fly: () => void;
}

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

Custom Type Guards

自定义类型守卫

typescript
// Type predicate function
interface Admin {
  role: "admin";
  permissions: string[];
}

interface User {
  role: "user";
  email: string;
}

type Person = Admin | User;

function isAdmin(person: Person): person is Admin {
  return person.role === "admin";
}

function handlePerson(person: Person) {
  if (isAdmin(person)) {
    console.log(person.permissions); // Admin type
  } else {
    console.log(person.email); // User type
  }
}

// Assertion function
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== "string") {
    throw new Error("Value must be a string");
  }
}

function processInput(input: unknown) {
  assertIsString(input);
  console.log(input.toUpperCase()); // TypeScript knows it's string
}

// Non-null assertion
function assertDefined<T>(value: T | null | undefined): asserts value is T {
  if (value === null || value === undefined) {
    throw new Error("Value must be defined");
  }
}

typescript
// 类型谓词函数
interface Admin {
  role: "admin";
  permissions: string[];
}

interface User {
  role: "user";
  email: string;
}

type Person = Admin | User;

function isAdmin(person: Person): person is Admin {
  return person.role === "admin";
}

function handlePerson(person: Person) {
  if (isAdmin(person)) {
    console.log(person.permissions); // Admin类型
  } else {
    console.log(person.email); // User类型
  }
}

// 断言函数
function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== "string") {
    throw new Error("值必须是字符串");
  }
}

function processInput(input: unknown) {
  assertIsString(input);
  console.log(input.toUpperCase()); // TypeScript 知道这是string类型
}

// 非空断言
function assertDefined<T>(value: T | null | undefined): asserts value is T {
  if (value === null || value === undefined) {
    throw new Error("值必须已定义");
  }
}

Function Types

函数类型

Function Signatures

函数签名

typescript
// Function type annotation
type MathOperation = (a: number, b: number) => number;

const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;

// Call signatures in interfaces
interface Calculator {
  (a: number, b: number): number;
  description: string;
}

const multiply: Calculator = Object.assign(
  (a: number, b: number) => a * b,
  { description: "Multiplies two numbers" }
);

// Overloads
function createElement(tag: "a"): HTMLAnchorElement;
function createElement(tag: "canvas"): HTMLCanvasElement;
function createElement(tag: "table"): HTMLTableElement;
function createElement(tag: string): HTMLElement;
function createElement(tag: string): HTMLElement {
  return document.createElement(tag);
}

const anchor = createElement("a"); // HTMLAnchorElement
const canvas = createElement("canvas"); // HTMLCanvasElement

// Generic function with constraints
function firstElement<T extends { length: number }>(arr: T): T[0] | undefined {
  return arr[0];
}

// Function with this parameter
interface Button {
  label: string;
  click(this: Button): void;
}

const button: Button = {
  label: "Submit",
  click() {
    console.log(this.label);
  },
};
typescript
// 函数类型注解
type MathOperation = (a: number, b: number) => number;

const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;

// 接口中的调用签名
interface Calculator {
  (a: number, b: number): number;
  description: string;
}

const multiply: Calculator = Object.assign(
  (a: number, b: number) => a * b,
  { description: "将两个数相乘" }
);

// 重载
function createElement(tag: "a"): HTMLAnchorElement;
function createElement(tag: "canvas"): HTMLCanvasElement;
function createElement(tag: "table"): HTMLTableElement;
function createElement(tag: string): HTMLElement;
function createElement(tag: string): HTMLElement {
  return document.createElement(tag);
}

const anchor = createElement("a"); // HTMLAnchorElement
const canvas = createElement("canvas"); // HTMLCanvasElement

// 带约束的泛型函数
function firstElement<T extends { length: number }>(arr: T): T[0] | undefined {
  return arr[0];
}

// 带this参数的函数
interface Button {
  label: string;
  click(this: Button): void;
}

const button: Button = {
  label: "提交",
  click() {
    console.log(this.label);
  },
};

Rest Parameters and Spread

剩余参数与展开

typescript
// Rest parameters
function sum(...numbers: number[]): number {
  return numbers.reduce((acc, n) => acc + n, 0);
}

// Typed rest parameters
function formatMessage(template: string, ...values: (string | number)[]): string {
  return values.reduce<string>(
    (msg, val, i) => msg.replace(`{${i}}`, String(val)),
    template
  );
}

// Variadic tuple types
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];

type Result = Concat<[1, 2], [3, 4]>; // [1, 2, 3, 4]

// Labeled tuple elements
function readButtonInput(...args: [name: string, version: number, ...input: boolean[]]) {
  const [name, version, ...input] = args;
}

typescript
// 剩余参数
function sum(...numbers: number[]): number {
  return numbers.reduce((acc, n) => acc + n, 0);
}

// 类型化剩余参数
function formatMessage(template: string, ...values: (string | number)[]): string {
  return values.reduce<string>(
    (msg, val, i) => msg.replace(`{${i}}`, String(val)),
    template
  );
}

// 可变元组类型
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U];

type Result = Concat<[1, 2], [3, 4]>; // [1, 2, 3, 4]

// 带标签的元组元素
function readButtonInput(...args: [name: string, version: number, ...input: boolean[]]) {
  const [name, version, ...input] = args;
}

Classes and OOP

类与面向对象

Class Fundamentals

类基础

typescript
class Animal {
  // Property declarations
  public name: string;
  protected species: string;
  private _age: number;
  readonly id: string;

  // Static members
  static kingdom = "Animalia";

  // Constructor
  constructor(name: string, species: string, age: number) {
    this.name = name;
    this.species = species;
    this._age = age;
    this.id = crypto.randomUUID();
  }

  // Getters and setters
  get age(): number {
    return this._age;
  }

  set age(value: number) {
    if (value < 0) throw new Error("Age cannot be negative");
    this._age = value;
  }

  // Methods
  speak(): void {
    console.log(`${this.name} makes a sound`);
  }

  // Static methods
  static isAnimal(obj: unknown): obj is Animal {
    return obj instanceof Animal;
  }
}

// Inheritance
class Dog extends Animal {
  breed: string;

  constructor(name: string, age: number, breed: string) {
    super(name, "Canis familiaris", age);
    this.breed = breed;
  }

  // Override method
  override speak(): void {
    console.log(`${this.name} barks!`);
  }
}
typescript
class Animal {
  // 属性声明
  public name: string;
  protected species: string;
  private _age: number;
  readonly id: string;

  // 静态成员
  static kingdom = "Animalia";

  // 构造函数
  constructor(name: string, species: string, age: number) {
    this.name = name;
    this.species = species;
    this._age = age;
    this.id = crypto.randomUUID();
  }

  // Getter与Setter
  get age(): number {
    return this._age;
  }

  set age(value: number) {
    if (value < 0) throw new Error("年龄不能为负数");
    this._age = value;
  }

  // 方法
  speak(): void {
    console.log(`${this.name} 发出了声音`);
  }

  // 静态方法
  static isAnimal(obj: unknown): obj is Animal {
    return obj instanceof Animal;
  }
}

// 继承
class Dog extends Animal {
  breed: string;

  constructor(name: string, age: number, breed: string) {
    super(name, "Canis familiaris", age);
    this.breed = breed;
  }

  // 重写方法
  override speak(): void {
    console.log(`${this.name} 汪汪叫!`);
  }
}

Abstract Classes

抽象类

typescript
abstract class Shape {
  abstract readonly name: string;
  abstract getArea(): number;
  abstract getPerimeter(): number;

  // Concrete method
  describe(): string {
    return `This is a ${this.name} with area ${this.getArea()}`;
  }
}

class Circle extends Shape {
  readonly name = "circle";

  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }

  getPerimeter(): number {
    return 2 * Math.PI * this.radius;
  }
}

class Rectangle extends Shape {
  readonly name = "rectangle";

  constructor(public width: number, public height: number) {
    super();
  }

  getArea(): number {
    return this.width * this.height;
  }

  getPerimeter(): number {
    return 2 * (this.width + this.height);
  }
}
typescript
abstract class Shape {
  abstract readonly name: string;
  abstract getArea(): number;
  abstract getPerimeter(): number;

  // 具体方法
  describe(): string {
    return `这是一个${this.name},面积为${this.getArea()}`;
  }
}

class Circle extends Shape {
  readonly name = "圆形";

  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }

  getPerimeter(): number {
    return 2 * Math.PI * this.radius;
  }
}

class Rectangle extends Shape {
  readonly name = "矩形";

  constructor(public width: number, public height: number) {
    super();
  }

  getArea(): number {
    return this.width * this.height;
  }

  getPerimeter(): number {
    return 2 * (this.width + this.height);
  }
}

Interfaces vs Types for Classes

类的接口与类型

typescript
// Interface for class implementation
interface Serializable {
  serialize(): string;
  deserialize(data: string): void;
}

interface Comparable<T> {
  compareTo(other: T): number;
}

class User implements Serializable, Comparable<User> {
  constructor(public id: number, public name: string) {}

  serialize(): string {
    return JSON.stringify({ id: this.id, name: this.name });
  }

  deserialize(data: string): void {
    const parsed = JSON.parse(data);
    this.id = parsed.id;
    this.name = parsed.name;
  }

  compareTo(other: User): number {
    return this.id - other.id;
  }
}

// Mixins pattern
type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    createdAt = new Date();
    updatedAt = new Date();

    touch() {
      this.updatedAt = new Date();
    }
  };
}

function Activatable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    isActive = false;

    activate() {
      this.isActive = true;
    }

    deactivate() {
      this.isActive = false;
    }
  };
}

class BaseEntity {
  id = crypto.randomUUID();
}

const TimestampedActivatableEntity = Timestamped(Activatable(BaseEntity));
const entity = new TimestampedActivatableEntity();
entity.activate();
entity.touch();

typescript
// 用于类实现的接口
interface Serializable {
  serialize(): string;
  deserialize(data: string): void;
}

interface Comparable<T> {
  compareTo(other: T): number;
}

class User implements Serializable, Comparable<User> {
  constructor(public id: number, public name: string) {}

  serialize(): string {
    return JSON.stringify({ id: this.id, name: this.name });
  }

  deserialize(data: string): void {
    const parsed = JSON.parse(data);
    this.id = parsed.id;
    this.name = parsed.name;
  }

  compareTo(other: User): number {
    return this.id - other.id;
  }
}

// 混入模式
type Constructor<T = {}> = new (...args: any[]) => T;

function Timestamped<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    createdAt = new Date();
    updatedAt = new Date();

    touch() {
      this.updatedAt = new Date();
    }
  };
}

function Activatable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {
    isActive = false;

    activate() {
      this.isActive = true;
    }

    deactivate() {
      this.isActive = false;
    }
  };
}

class BaseEntity {
  id = crypto.randomUUID();
}

const TimestampedActivatableEntity = Timestamped(Activatable(BaseEntity));
const entity = new TimestampedActivatableEntity();
entity.activate();
entity.touch();

Module System

模块系统

Export Patterns

导出模式

typescript
// Named exports
export const API_URL = "https://api.example.com";
export type UserID = string;
export interface User {
  id: UserID;
  name: string;
}

export function fetchUser(id: UserID): Promise<User> {
  return fetch(`${API_URL}/users/${id}`).then((r) => r.json());
}

// Default export
export default class UserService {
  async getUser(id: string): Promise<User> {
    return fetchUser(id);
  }
}

// Re-exports
export { User as UserModel } from "./user";
export * from "./types";
export * as utils from "./utils";

// Type-only exports
export type { User, UserID };
typescript
// 命名导出
export const API_URL = "https://api.example.com";
export type UserID = string;
export interface User {
  id: UserID;
  name: string;
}

export function fetchUser(id: UserID): Promise<User> {
  return fetch(`${API_URL}/users/${id}`).then((r) => r.json());
}

// 默认导出
export default class UserService {
  async getUser(id: string): Promise<User> {
    return fetchUser(id);
  }
}

// 重导出
export { User as UserModel } from "./user";
export * from "./types";
export * as utils from "./utils";

// 仅类型导出
export type { User, UserID };

Declaration Files

声明文件

typescript
// types.d.ts - Ambient declarations

// Declare module for untyped package
declare module "untyped-library" {
  export function doSomething(value: string): number;
  export const version: string;
}

// Extend existing module
declare module "express" {
  interface Request {
    user?: {
      id: string;
      role: string;
    };
  }
}

// Global declarations
declare global {
  interface Window {
    myApp: {
      version: string;
      config: Record<string, unknown>;
    };
  }

  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: "development" | "production" | "test";
      API_URL: string;
      DATABASE_URL: string;
    }
  }
}

// Ambient namespace
declare namespace MyNamespace {
  interface Config {
    apiKey: string;
    baseUrl: string;
  }

  function initialize(config: Config): void;
}

typescript
// types.d.ts - 环境声明

// 为无类型包声明模块
declare module "untyped-library" {
  export function doSomething(value: string): number;
  export const version: string;
}

// 扩展现有模块
declare module "express" {
  interface Request {
    user?: {
      id: string;
      role: string;
    };
  }
}

// 全局声明
declare global {
  interface Window {
    myApp: {
      version: string;
      config: Record<string, unknown>;
    };
  }

  namespace NodeJS {
    interface ProcessEnv {
      NODE_ENV: "development" | "production" | "test";
      API_URL: string;
      DATABASE_URL: string;
    }
  }
}

// 环境命名空间
declare namespace MyNamespace {
  interface Config {
    apiKey: string;
    baseUrl: string;
  }

  function initialize(config: Config): void;
}

Best Practices

最佳实践

Error Handling

错误处理

typescript
// Result type pattern
type Result<T, E = Error> =
  | { ok: true; value: T }
  | { ok: false; error: E };

function ok<T>(value: T): Result<T, never> {
  return { ok: true, value };
}

function err<E>(error: E): Result<never, E> {
  return { ok: false, error };
}

async function fetchUser(id: string): Promise<Result<User, string>> {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      return err(`HTTP ${response.status}: ${response.statusText}`);
    }
    const user = await response.json();
    return ok(user);
  } catch (e) {
    return err(e instanceof Error ? e.message : "Unknown error");
  }
}

// Usage
async function handleUser(id: string) {
  const result = await fetchUser(id);

  if (result.ok) {
    console.log(result.value.name);
  } else {
    console.error(result.error);
  }
}
typescript
// 结果类型模式
type Result<T, E = Error> =
  | { ok: true; value: T }
  | { ok: false; error: E };

function ok<T>(value: T): Result<T, never> {
  return { ok: true, value };
}

function err<E>(error: E): Result<never, E> {
  return { ok: false, error };
}

async function fetchUser(id: string): Promise<Result<User, string>> {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      return err(`HTTP ${response.status}: ${response.statusText}`);
    }
    const user = await response.json();
    return ok(user);
  } catch (e) {
    return err(e instanceof Error ? e.message : "未知错误");
  }
}

// 使用示例
async function handleUser(id: string) {
  const result = await fetchUser(id);

  if (result.ok) {
    console.log(result.value.name);
  } else {
    console.error(result.error);
  }
}

Immutability Patterns

不可变模式

typescript
// as const for literal types
const config = {
  api: {
    url: "https://api.example.com",
    timeout: 5000,
  },
  features: ["auth", "analytics"],
} as const;

type Config = typeof config;
type Feature = (typeof config.features)[number]; // "auth" | "analytics"

// Readonly utilities
interface State {
  user: User | null;
  items: Item[];
  settings: Settings;
}

type ImmutableState = Readonly<State>;
type DeepImmutableState = {
  readonly [K in keyof State]: Readonly<State[K]>;
};

// Immutable update pattern
function updateState<T extends object, K extends keyof T>(
  state: T,
  key: K,
  value: T[K]
): T {
  return { ...state, [key]: value };
}
typescript
// as const 用于字面量类型
const config = {
  api: {
    url: "https://api.example.com",
    timeout: 5000,
  },
  features: ["auth", "analytics"],
} as const;

type Config = typeof config;
type Feature = (typeof config.features)[number]; // "auth" | "analytics"

// 只读工具
interface State {
  user: User | null;
  items: Item[];
  settings: Settings;
}

type ImmutableState = Readonly<State>;
type DeepImmutableState = {
  readonly [K in keyof State]: Readonly<State[K]>;
};

// 不可变更新模式
function updateState<T extends object, K extends keyof T>(
  state: T,
  key: K,
  value: T[K]
): T {
  return { ...state, [key]: value };
}

Strict Null Checks

严格空检查

typescript
// Handling nullable values
function processUser(user: User | null | undefined): string {
  // Optional chaining
  const name = user?.name ?? "Anonymous";

  // Nullish coalescing
  const email = user?.email ?? "no-email@example.com";

  // Non-null assertion (use sparingly!)
  // const id = user!.id;

  return `${name} (${email})`;
}

// Type narrowing
function getLength(value: string | null): number {
  if (value === null) {
    return 0;
  }
  return value.length; // TypeScript knows it's string
}

// Assert non-null with custom message
function assertNonNull<T>(
  value: T | null | undefined,
  message: string
): asserts value is T {
  if (value === null || value === undefined) {
    throw new Error(message);
  }
}

typescript
// 处理可空值
function processUser(user: User | null | undefined): string {
  // 可选链
  const name = user?.name ?? "匿名用户";

  // 空值合并
  const email = user?.email ?? "no-email@example.com";

  // 非空断言(谨慎使用!)
  // const id = user!.id;

  return `${name} (${email})`;
}

// 类型收窄
function getLength(value: string | null): number {
  if (value === null) {
    return 0;
  }
  return value.length; // TypeScript 知道这是string类型
}

// 带自定义消息的非空断言
function assertNonNull<T>(
  value: T | null | undefined,
  message: string
): asserts value is T {
  if (value === null || value === undefined) {
    throw new Error(message);
  }
}

tsconfig.json Best Practices

tsconfig.json 最佳实践

json
{
  "compilerOptions": {
    // Strict type checking
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "useUnknownInCatchVariables": true,
    "alwaysStrict": true,

    // Additional checks
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,

    // Module resolution
    "moduleResolution": "bundler",
    "module": "ESNext",
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],

    // Output
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",

    // Interop
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "resolveJsonModule": true,

    // Path mapping
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/utils/*": ["./src/utils/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

json
{
  "compilerOptions": {
    // 严格类型检查
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "useUnknownInCatchVariables": true,
    "alwaysStrict": true,

    // 额外检查
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,

    // 模块解析
    "moduleResolution": "bundler",
    "module": "ESNext",
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],

    // 输出
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",

    // 互操作性
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true,
    "isolatedModules": true,
    "resolveJsonModule": true,

    // 路径映射
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/utils/*": ["./src/utils/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist", "**/*.test.ts"]
}

Лучшие практики

最佳实践

  1. Включай strict mode — это основа type safety
  2. Избегай any — используй unknown для неизвестных типов
  3. Явно типизируй публичные API — функции, классы, интерфейсы
  4. Используй discriminated unions для сложных состояний
  5. Применяй readonly для иммутабельных данных
  6. Создавай type guards вместо type assertions
  7. Используй template literal types для строковых паттернов
  8. Организуй типы в отдельные файлы — .types.ts, index.d.ts
  1. 启用严格模式 —— 这是类型安全的基础
  2. 避免使用any —— 对未知类型使用unknown
  3. 显式声明公开API —— 函数、类、接口
  4. 使用可区分联合类型 处理复杂状态
  5. 对不可变数据使用readonly
  6. 创建类型守卫 而非类型断言
  7. 使用模板字面量类型 处理字符串模式
  8. 将类型组织到单独文件中 —— .types.ts、index.d.ts