typescript

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

When to Use

适用场景

Triggers: When writing TypeScript, defining types/interfaces, or using utility types.
Load when: writing TypeScript code, defining data structures, working with generics, or needing type safety patterns.
触发场景:编写 TypeScript 代码、定义类型/接口或使用工具类型时。
适用时机:编写 TypeScript 代码、定义数据结构、使用泛型或需要类型安全模式时。

Critical Patterns

核心模式

Pattern 1: Const Types (single source of truth)

模式1:常量类型(单一数据源)

typescript
// ✅ Create const object first, then extract type
const USER_ROLES = {
  ADMIN: 'admin',
  USER: 'user',
  GUEST: 'guest',
} as const;

type UserRole = typeof USER_ROLES[keyof typeof USER_ROLES];
// UserRole = 'admin' | 'user' | 'guest'

// ❌ Avoid: direct union types lose runtime values
type UserRole = 'admin' | 'user' | 'guest';
typescript
// ✅ Create const object first, then extract type
const USER_ROLES = {
  ADMIN: 'admin',
  USER: 'user',
  GUEST: 'guest',
} as const;

type UserRole = typeof USER_ROLES[keyof typeof USER_ROLES];
// UserRole = 'admin' | 'user' | 'guest'

// ❌ Avoid: direct union types lose runtime values
type UserRole = 'admin' | 'user' | 'guest';

Pattern 2: Flat Interfaces (one-level depth)

模式2:扁平化接口(单层结构)

typescript
// ✅ Flat, composable interfaces
interface Address {
  street: string;
  city: string;
  country: string;
}

interface User {
  id: string;
  name: string;
  address: Address; // Reference, not inline
}

interface Admin extends User {
  permissions: string[];
}

// ❌ Avoid: deeply nested inline types
interface User {
  address: {
    street: string;
    location: {
      city: string;
      coords: { lat: number; lng: number };
    };
  };
}
typescript
// ✅ Flat, composable interfaces
interface Address {
  street: string;
  city: string;
  country: string;
}

interface User {
  id: string;
  name: string;
  address: Address; // Reference, not inline
}

interface Admin extends User {
  permissions: string[];
}

// ❌ Avoid: deeply nested inline types
interface User {
  address: {
    street: string;
    location: {
      city: string;
      coords: { lat: number; lng: number };
    };
  };
}

Pattern 3: Avoid
any
— Use
unknown
or generics

模式3:避免使用
any
—— 改用
unknown
或泛型

typescript
// ✅ Use unknown with type guard
function processData(data: unknown): string {
  if (typeof data === 'string') return data;
  if (typeof data === 'number') return data.toString();
  throw new Error('Unsupported type');
}

// ✅ Use generics for flexible typing
function getFirst<T>(arr: T[]): T | undefined {
  return arr[0];
}

// ❌ Avoid
function processData(data: any): any {
  return data.toString(); // No type safety
}
typescript
// ✅ Use unknown with type guard
function processData(data: unknown): string {
  if (typeof data === 'string') return data;
  if (typeof data === 'number') return data.toString();
  throw new Error('Unsupported type');
}

// ✅ Use generics for flexible typing
function getFirst<T>(arr: T[]): T | undefined {
  return arr[0];
}

// ❌ Avoid
function processData(data: any): any {
  return data.toString(); // No type safety
}

Code Examples

代码示例

Utility Types

Utility Types(工具类型)

typescript
interface User {
  id: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// Pick specific fields
type UserPublic = Pick<User, 'id' | 'name' | 'email'>;

// Omit sensitive fields
type UserWithoutPassword = Omit<User, 'password'>;

// All fields optional (for updates)
type UserUpdate = Partial<User>;

// All fields required
type UserRequired = Required<User>;

// All fields readonly
type UserReadonly = Readonly<User>;

// Map of users
type UsersMap = Record<string, User>;

// Extract subset of union
type AdminOrUser = Extract<UserRole, 'admin' | 'user'>;

// Return type of function
type LoginResult = ReturnType<typeof loginUser>;

// Parameters of function
type LoginParams = Parameters<typeof loginUser>;
typescript
interface User {
  id: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// Pick specific fields
type UserPublic = Pick<User, 'id' | 'name' | 'email'>;

// Omit sensitive fields
type UserWithoutPassword = Omit<User, 'password'>;

// All fields optional (for updates)
type UserUpdate = Partial<User>;

// All fields required
type UserRequired = Required<User>;

// All fields readonly
type UserReadonly = Readonly<User>;

// Map of users
type UsersMap = Record<string, User>;

// Extract subset of union
type AdminOrUser = Extract<UserRole, 'admin' | 'user'>;

// Return type of function
type LoginResult = ReturnType<typeof loginUser>;

// Parameters of function
type LoginParams = Parameters<typeof loginUser>;

Type Guards

Type Guards(类型守卫)

typescript
// ✅ Type guard with `is` syntax
function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value
  );
}

// Discriminated union
type ApiResponse<T> =
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

function handleResponse<T>(response: ApiResponse<T>) {
  if (response.status === 'success') {
    console.log(response.data); // TypeScript knows data exists
  } else {
    console.error(response.message); // TypeScript knows message exists
  }
}
typescript
// ✅ Type guard with `is` syntax
function isUser(value: unknown): value is User {
  return (
    typeof value === 'object' &&
    value !== null &&
    'id' in value &&
    'name' in value
  );
}

// Discriminated union
type ApiResponse<T> =
  | { status: 'success'; data: T }
  | { status: 'error'; message: string };

function handleResponse<T>(response: ApiResponse<T>) {
  if (response.status === 'success') {
    console.log(response.data); // TypeScript knows data exists
  } else {
    console.error(response.message); // TypeScript knows message exists
  }
}

Import Types

Import Types(类型导入)

typescript
// ✅ Use import type for type-only imports
import type { User, UserRole } from './types';
import type { FC, ReactNode } from 'react';

// Runtime imports
import { useState } from 'react';
import { createUser } from './services/user';
typescript
// ✅ Use import type for type-only imports
import type { User, UserRole } from './types';
import type { FC, ReactNode } from 'react';

// Runtime imports
import { useState } from 'react';
import { createUser } from './services/user';

Readonly and Immutability

只读与不可变性

typescript
// ✅ Immutable data structures
const config: Readonly<{
  apiUrl: string;
  timeout: number;
}> = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
};

// Deep readonly
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
typescript
// ✅ Immutable data structures
const config: Readonly<{
  apiUrl: string;
  timeout: number;
}> = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
};

// Deep readonly
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};

Anti-Patterns

反模式

❌ Using
any

❌ 使用
any

typescript
// ❌ Bad
function parse(data: any) {
  return data.value; // No type safety
}

// ✅ Good
function parse(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String((data as { value: unknown }).value);
  }
  throw new Error('Invalid data shape');
}
typescript
// ❌ Bad
function parse(data: any) {
  return data.value; // No type safety
}

// ✅ Good
function parse(data: unknown): string {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return String((data as { value: unknown }).value);
  }
  throw new Error('Invalid data shape');
}

❌ Non-null assertion without guard

❌ 无守卫的非空断言

typescript
// ❌ Bad - runtime crash if null
const user = getUser()!;
console.log(user.name);

// ✅ Good
const user = getUser();
if (!user) throw new Error('User not found');
console.log(user.name);
typescript
// ❌ Bad - runtime crash if null
const user = getUser()!;
console.log(user.name);

// ✅ Good
const user = getUser();
if (!user) throw new Error('User not found');
console.log(user.name);

Quick Reference

速查表

TaskPattern
Union from object
typeof OBJ[keyof typeof OBJ]
Optional fields
Partial<T>
Pick fields
Pick<T, 'a' | 'b'>
Exclude fields
Omit<T, 'password'>
Type guard
value is Type
Type-only import
import type { T }
Readonly
Readonly<T>
or
as const
Generic constraint
<T extends object>
任务模式
从对象生成联合类型
typeof OBJ[keyof typeof OBJ]
可选字段
Partial<T>
选取指定字段
Pick<T, 'a' | 'b'>
排除指定字段
Omit<T, 'password'>
类型守卫
value is Type
仅类型导入
import type { T }
只读
Readonly<T>
as const
泛型约束
<T extends object>

Rules

规则

  • any
    is forbidden — use
    unknown
    with type guards or generics;
    @ts-ignore
    is only acceptable as a last resort with an explanatory comment
  • Use
    import type
    for type-only imports to ensure they are erased at compile time and do not affect the runtime bundle
  • Prefer
    const
    objects with
    as const
    over plain union types for enums and string literals — this preserves runtime values alongside the type
  • Non-null assertions (
    !
    ) require an immediately preceding null check; bare
    value!
    without a guard is a runtime crash waiting to happen
  • Interfaces should be flat and composable — deeply nested inline type definitions inside other types are a readability and reusability anti-pattern
  • 禁止使用
    any
    —— 改用带类型守卫的
    unknown
    或泛型;仅在万不得已且添加解释性注释的情况下,才可使用
    @ts-ignore
  • 仅类型导入时使用
    import type
    ,确保其在编译时被移除,不影响运行时包体积
  • 对于枚举和字符串字面量,优先选择带
    as const
    的常量对象而非普通联合类型 —— 这样可同时保留运行时值和类型
  • 非空断言(
    !
    )必须紧跟空值检查;无守卫的
    value!
    可能导致运行时崩溃
  • 接口应扁平化且可组合 —— 在其他类型内部定义深度嵌套的内联类型是影响可读性和复用性的反模式