TypeScript类型系统Skill typescript-type-system

TypeScript类型系统技能专注于TypeScript语言的类型特性,包括编译器配置、严格模式、高级类型(如联合与交叉类型、泛型、条件类型、映射类型、模板字面量类型)、类型收窄(类型守卫、判别联合)、实用类型、类型断言等,帮助开发者编写类型安全的JavaScript代码,提高代码质量和可维护性,适用于前端和后端开发。关键词:TypeScript, 类型系统, 严格模式, 泛型, 类型守卫, 编译器配置, 前端开发, 后端开发, 类型安全, 代码质量。

前端开发 1 次安装 2 次浏览 更新于 3/25/2026

name: typescript-type-system user-invocable: false description: 用于处理TypeScript类型系统,包括严格模式、高级类型、泛型、类型守卫和编译器配置。 allowed-tools:

  • Bash
  • Read

TypeScript类型系统

掌握TypeScript的类型系统特性以编写类型安全的代码。此技能专注于TypeScript语言能力。

TypeScript编译器

# 类型检查而不生成文件
tsc --noEmit

# 使用特定配置进行类型检查
tsc --noEmit -p tsconfig.json

# 显示编译器版本
tsc --version

# 开发模式下的监视模式
tsc --noEmit --watch

严格模式配置

tsconfig.json严格模式选项:

{
  "compilerOptions": {
    "strict": true,                           // 启用所有严格选项
    "noImplicitAny": true,                    // 对'any'报错
    "strictNullChecks": true,                 // null必须显式
    "strictFunctionTypes": true,              // 更严格的函数类型
    "strictBindCallApply": true,              // 严格的bind/call/apply
    "strictPropertyInitialization": true,     // 类初始化必需
    "noImplicitThis": true,                   // 对'this' any报错
    "alwaysStrict": true,                     // 解析严格模式
    "useUnknownInCatchVariables": true        // catch变量为'unknown'
  }
}

基本编译器选项

{
  "compilerOptions": {
    // 类型检查
    "exactOptionalPropertyTypes": true,       // 区分undefined和缺失
    "noFallthroughCasesInSwitch": true,      // 防止switch中的fallthrough
    "noImplicitOverride": true,               // 要求'override'关键字
    "noImplicitReturns": true,                // 所有代码路径必须返回
    "noPropertyAccessFromIndexSignature": true, // 对索引要求括号表示法
    "noUncheckedIndexedAccess": true,         // 索引签名返回T | undefined
    "noUnusedLocals": true,                   // 对未使用的局部变量报错
    "noUnusedParameters": true,               // 对未使用的参数报错

    // 模块解析
    "moduleResolution": "bundler",            // 现代打包器解析
    "resolveJsonModule": true,                // 导入JSON文件
    "allowImportingTsExtensions": true,       // 导入.ts/.tsx文件
    "allowSyntheticDefaultImports": true,     // 允许从模块默认导入
    "esModuleInterop": true,                  // 为CommonJS互操作生成辅助

    // 生成
    "declaration": true,                      // 生成.d.ts文件
    "declarationMap": true,                   // .d.ts的源映射
    "sourceMap": true,                        // 生成.map文件
    "removeComments": false,                  // 在输出中保留注释
    "importHelpers": true,                    // 从tslib导入辅助

    // 互操作约束
    "isolatedModules": true,                  // 每个文件可单独转译
    "allowArbitraryExtensions": true,         // 允许任何扩展名的导入
    "verbatimModuleSyntax": false,            // 保留导入/导出语法

    // 跳过检查
    "skipLibCheck": true                      // 跳过.d.ts文件检查
  }
}

高级类型模式

联合与交叉类型

// 联合类型(或)
type Status = "pending" | "active" | "completed";
type ID = string | number;
type Result = Success | Error;

// 交叉类型(与)
type User = Person & Employee;
type Props = BaseProps & { extended: true };

// 判别联合
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; size: number }
  | { kind: "rectangle"; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.size ** 2;
    case "rectangle":
      return shape.width * shape.height;
  }
}

泛型

// 基本泛型
function identity<T>(value: T): T {
  return value;
}

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

// 多类型参数
function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

// 泛型接口
interface Repository<T> {
  find(id: string): Promise<T | null>;
  save(entity: T): Promise<T>;
  delete(id: string): Promise<void>;
}

// 泛型类
class DataStore<T extends { id: string }> {
  private items = new Map<string, T>();

  add(item: T): void {
    this.items.set(item.id, item);
  }

  get(id: string): T | undefined {
    return this.items.get(id);
  }
}

// 默认类型参数
type Response<T = unknown> = {
  data: T;
  status: number;
};

条件类型

// 基本条件类型
type IsString<T> = T extends string ? true : false;

// 分配条件类型
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;

// infer关键字
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

// 嵌套条件
type Flatten<T> = T extends Array<infer U> ? U : T;
type DeepFlatten<T> = T extends Array<infer U> ? DeepFlatten<U> : T;

// 带约束的条件类型
type NonNullable<T> = T extends null | undefined ? never : T;

映射类型

// 使所有属性可选
type Partial<T> = {
  [P in keyof T]?: T[P];
};

// 使所有属性必需
type Required<T> = {
  [P in keyof T]-?: T[P];
};

// 使所有属性只读
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 选取特定属性
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

// 省略特定属性
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

// 转换属性类型
type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

// 映射类型中的键重映射
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

// 按类型过滤属性
type PickByType<T, U> = {
  [P in keyof T as T[P] extends U ? P : never]: T[P];
};

模板字面量类型

// 基本模板字面量
type EventName = "click" | "focus" | "blur";
type Handler = `on${Capitalize<EventName>}`; // "onClick" | "onFocus" | "onBlur"

// 组合模板字面量
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = `/api/${string}`;
type Route = `${HTTPMethod} ${Endpoint}`;

// 从模板提取模式
type ExtractRouteParams<T extends string> =
  T extends `${string}:${infer Param}/${infer Rest}`
    ? Param | ExtractRouteParams<Rest>
    : T extends `${string}:${infer Param}`
    ? Param
    : never;

type Params = ExtractRouteParams<"/users/:userId/posts/:postId">; // "userId" | "postId"

// 大写/小写/首字母大写/非首字母大写
type UppercaseKeys<T> = {
  [K in keyof T as Uppercase<string & K>]: T[K];
};

类型收窄

类型守卫

// typeof类型守卫
function process(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // value是字符串
  }
  return value.toFixed(2); // value是数字
}

// instanceof类型守卫
class Dog {
  bark() {}
}
class Cat {
  meow() {}
}

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

// in运算符收窄
type Fish = { swim: () => void };
type Bird = { fly: () => void };

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

// 自定义类型守卫
function isString(value: unknown): value is string {
  return typeof value === "string";
}

function isUser(obj: unknown): obj is { name: string; age: number } {
  return (
    typeof obj === "object" &&
    obj !== null &&
    "name" in obj &&
    "age" in obj &&
    typeof obj.name === "string" &&
    typeof obj.age === "number"
  );
}

// 断言函数
function assert(condition: unknown, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== "string") {
    throw new Error("不是字符串");
  }
}

判别联合

// 使用字面量类型作为判别器
type NetworkState =
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; error: Error };

function handleNetwork(state: NetworkState) {
  switch (state.status) {
    case "loading":
      return "加载中...";
    case "success":
      return state.data; // data可用
    case "error":
      return state.error.message; // error可用
  }
}

// 多判别器
type Response =
  | { kind: "ok"; status: 200; data: string }
  | { kind: "redirect"; status: 301 | 302; location: string }
  | { kind: "error"; status: 400 | 500; message: string };

真值收窄

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    // strs是string[]
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    // strs是字符串
    console.log(strs);
  }
}

实用类型

内置实用类型

// Partial - 使所有属性可选
type User = { name: string; age: number };
type PartialUser = Partial<User>; // { name?: string; age?: number }

// Required - 使所有属性必需
type RequiredUser = Required<PartialUser>; // { name: string; age: number }

// Readonly - 使所有属性只读
type ReadonlyUser = Readonly<User>;
// { readonly name: string; readonly age: number }

// Record - 构造键为K、值为T的对象类型
type PageInfo = Record<"home" | "about" | "contact", { title: string }>;

// Pick - 从类型中选取属性
type UserName = Pick<User, "name">; // { name: string }

// Omit - 从类型中省略属性
type UserWithoutAge = Omit<User, "age">; // { name: string }

// Exclude - 从联合中排除类型
type T = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// Extract - 从联合中提取类型
type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

// NonNullable - 移除null和undefined
type T3 = NonNullable<string | null | undefined>; // string

// ReturnType - 获取函数返回类型
function f() { return { x: 10, y: 3 }; }
type P = ReturnType<typeof f>; // { x: number; y: number }

// Parameters - 获取参数类型为元组
function f2(a: string, b: number) {}
type P2 = Parameters<typeof f2>; // [string, number]

// ConstructorParameters - 获取构造函数参数类型
class C {
  constructor(a: string, b: number) {}
}
type CP = ConstructorParameters<typeof C>; // [string, number]

// InstanceType - 获取构造函数实例类型
type CT = InstanceType<typeof C>; // C

// Awaited - 获取Promise返回的类型
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number

类型断言和转换

// 类型断言(尖括号语法 - 在JSX中避免使用)
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;

// 类型断言(as语法 - 首选)
let strLength2: number = (someValue as string).length;

// 非空断言运算符
function liveDangerously(x?: number | null) {
  console.log(x!.toFixed()); // x肯定不为null/undefined
}

// 常量断言
let x = "hello" as const; // 类型为"hello",不是string
let y = [10, 20] as const; // 类型为readonly [10, 20]
let z = { text: "hello" } as const; // 类型为{ readonly text: "hello" }

// 双重断言(逃生口 - 谨慎使用)
const a = (expr as unknown) as T;

// satisfies运算符(检查类型而不加宽)
type Color = { r: number; g: number; b: number } | string;

const red = { r: 255, g: 0, b: 0 } satisfies Color;
const blue = "#0000FF" satisfies Color;

仅类型导入和导出

// 仅导入类型(运行时擦除)
import type { User, Product } from "./types";
import type * as Types from "./types";

// 混合导入
import { type User, createUser } from "./user";

// 仅导出类型
export type { User, Product };
export type * from "./types";

// 内联类型导入(verbatimModuleSyntax: false时)
import { type User } from "./user";

索引签名和映射类型

// 基本索引签名
interface StringMap {
  [key: string]: string;
}

// 数字索引签名
interface NumberArray {
  [index: number]: number;
}

// 带已知属性的索引签名
interface Dictionary {
  [key: string]: string;
  name: string; // OK: string可赋值给string
}

// 模板字面量在索引签名中
interface Events {
  [key: `on${string}`]: (event: Event) => void;
}

// 使用索引签名访问(带noUncheckedIndexedAccess)
interface Data {
  [key: string]: number;
}

const data: Data = {};
const value = data["key"]; // 类型为number | undefined

// 使用Record避免索引签名
type SafeData = Record<string, number>;

高级模式

品牌类型

// 通过品牌实现名义类型
type Brand<K, T> = K & { __brand: T };

type UserId = Brand<string, "UserId">;
type OrderId = Brand<string, "OrderId">;

function createUserId(id: string): UserId {
  return id as UserId;
}

function getUserById(id: UserId) {
  // id必须是UserId
}

const userId = createUserId("123");
const orderId = "456" as OrderId;

getUserById(userId); // OK
// getUserById(orderId); // 错误:OrderId不可赋值给UserId

构建器模式与流畅API

class QueryBuilder<T> {
  private filters: Array<(item: T) => boolean> = [];

  where(predicate: (item: T) => boolean): this {
    this.filters.push(predicate);
    return this;
  }

  execute(items: T[]): T[] {
    return items.filter(item =>
      this.filters.every(filter => filter(item))
    );
  }
}

// 使用类型推断
const users = new QueryBuilder<{ name: string; age: number }>()
  .where(u => u.age > 18)
  .where(u => u.name.startsWith("A"))
  .execute(allUsers);

可变元组类型

// 在元组类型中展开
type Tuple1 = [string, number];
type Tuple2 = [boolean, ...Tuple1]; // [boolean, string, number]

// 泛型剩余参数
function concat<T extends unknown[], U extends unknown[]>(
  arr1: [...T],
  arr2: [...U]
): [...T, ...U] {
  return [...arr1, ...arr2];
}

// 带标签的元组元素
type Range = [start: number, end: number];
type Point = [x: number, y: number, z?: number];

常见类型模式

递归类型

// 递归对象类型
type JSONValue =
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue };

// 递归元组
type NestedArray<T> = T | NestedArray<T>[];

// 深部分
type DeepPartial<T> = T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T;

函数重载

// 函数重载签名
function createElement(tag: "div"): HTMLDivElement;
function createElement(tag: "span"): HTMLSpanElement;
function createElement(tag: "canvas"): HTMLCanvasElement;
function createElement(tag: string): HTMLElement {
  return document.createElement(tag);
}

// 方法重载
class EventEmitter {
  on(event: "data", handler: (data: string) => void): void;
  on(event: "error", handler: (error: Error) => void): void;
  on(event: string, handler: (arg: any) => void): void {
    // 实现
  }
}

带泛型的类型谓词

// 泛型类型守卫
function isDefined<T>(value: T | null | undefined): value is T {
  return value !== null && value !== undefined;
}

const values = [1, null, 2, undefined, 3];
const numbers = values.filter(isDefined); // number[]

// 数组元素类型守卫
function isArrayOf<T>(
  arr: unknown,
  check: (item: unknown) => item is T
): arr is T[] {
  return Array.isArray(arr) && arr.every(check);
}

tsconfig.json最佳实践

项目引用

{
  "compilerOptions": {
    "composite": true,                        // 启用项目引用
    "declarationMap": true,                   // 声明的源映射
    "incremental": true,                      // 增量编译
    "tsBuildInfoFile": "./buildinfo"          // 构建信息缓存位置
  },
  "references": [
    { "path": "../shared" },
    { "path": "../utils" }
  ]
}

路径映射

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"],
      "@types/*": ["src/types/*"]
    }
  }
}

多配置

// tsconfig.json(基础)
{
  "compilerOptions": {
    "strict": true,
    "skipLibCheck": true
  }
}

// tsconfig.build.json(扩展基础)
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "declaration": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.test.ts"]
}

类型系统限制

TypeScript无法做到的事情

// 无法在运行时检查(类型被擦除)
function process<T>(value: T) {
  // 错误:不能在运行时使用'T'
  // if (value instanceof T) {}
}

// 无法使用类型作为值
type User = { name: string };
// const user = new User(); // 错误:User是类型,不是值

// 名义类型(TypeScript使用结构类型)
type USD = number;
type EUR = number;
const usd: USD = 100;
const eur: EUR = usd; // TypeScript中OK(两者都是数字)

// 精确类型(TypeScript在某些情况下允许多余属性)
type Point = { x: number; y: number };
const p: Point = { x: 1, y: 2, z: 3 }; // 错误(对象字面量)
const obj = { x: 1, y: 2, z: 3 };
const p2: Point = obj; // OK(非对象字面量)

资源