前置知识: JavaScript

TypeScript 语法速查

00:00
1 min Beginner

常用 TypeScript 语法速查表,含使用场景、常见错误,支持搜索和复制

学习指引

前置知识

  • 掌握 JavaScript 基础语法
  • 了解类型系统的基本概念

推荐学习顺序

  1. 先学习【类型系统】分组,掌握基础类型、接口和联合类型
  2. 再学习【泛型】分组,掌握泛型函数、泛型约束和条件类型

类型系统

TypeScript 的核心价值。本组内容涵盖基础类型、接口、类型别名、联合类型和枚举,是编写类型安全代码的基础。

基础类型

let username: string = "张三";
let age: number = 25;
let isActive: boolean = true;
let items: string[] = ["苹果", "香蕉"];
let id: number | string = 1001;

// 函数类型注解
function greet(name: string): string {
  return `你好, ${name}`;
}
输出: 所有变量具有明确的类型约束,编译时检查类型错误
场景: 为变量、函数参数和返回值添加类型注解。TypeScript 的基础类型包括 string、number、boolean、array、tuple、enum、void、null、undefined、never 等。

常见错误

  • 错误: let age: number = "25"; -- 解决: 确保赋值类型与声明类型一致:let age: number = 25
  • 错误: let items = [];(空数组推断为 never[]) -- 解决: 声明时指定类型:let items: string[] = []
进阶: TypeScript 支持类型推断,变量初始化时可省略类型注解。但函数参数必须显式注解,返回值通常可推断。

接口

interface User {
  id: number;
  name: string;
  email: string;
  age?: number;
  readonly createdAt: Date;
}

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@mail.com",
  createdAt: new Date()
};
输出: user 对象符合 User 接口的类型约束,缺少必填字段会报错
场景: 定义对象的形状(shape)。接口描述了对象应该有哪些属性及其类型。? 标记可选属性,readonly 标记只读属性。接口可扩展和实现。

常见错误

  • 错误: const user: User = { id: 1, name: "张三" }; -- 解决: 必须包含所有非可选属性,或将 email 标记为可选:email?: string
  • 错误: user.createdAt = new Date();(修改只读属性) -- 解决: readonly 属性只能在初始化时赋值,之后不可修改
进阶: 接口可继承:interface Admin extends User { permissions: string[] }。接口也可描述函数类型和可索引类型。

类型别名

type ID = number | string;
type Point = { x: number; y: number };
type Callback = (data: string) => void;

const userId: ID = 1001;
const point: Point = { x: 10, y: 20 };
const handler: Callback = (data) => console.log(data);
输出: 各变量使用类型别名进行约束,类型检查通过
场景: 为类型创建别名。与接口类似但更灵活:可给联合类型、交叉类型、基本类型等创建别名。适合复杂类型的复用和简化。

常见错误

  • 错误: type User = { name: string } & { name: number };(冲突的交叉类型) -- 解决: 交叉类型的同名属性类型必须兼容,否则合并为 never
  • 错误: type Point = { x: number; y: number }; interface Point { z: number; }(类型别名与接口同名) -- 解决: 类型别名不能像接口那样声明合并,改用接口或使用不同的名称
进阶: 接口和类型别名的主要区别:接口可声明合并(同名自动合并),类型别名更灵活(支持联合/交叉/映射类型)。定义对象形状优先用接口,其他场景用类型别名。

联合类型

// 联合类型
type Status = "pending" | "active" | "inactive";
let currentStatus: Status = "active";

// 可辨识联合
type SuccessResponse = { status: "success"; data: string };
type ErrorResponse = { status: "error"; message: string };
type ApiResponse = SuccessResponse | ErrorResponse;

function handleResponse(res: ApiResponse) {
  if (res.status === "success") {
    console.log(res.data); // TypeScript 知道此处是 SuccessResponse
  } else {
    console.log(res.message); // TypeScript 知道此处是 ErrorResponse
  }
}
输出: currentStatus 只能赋值为三个字符串之一,handleResponse 中通过 status 字段自动收窄类型
场景: 联合类型允许一个值是多种类型之一。字面量联合类型可限制为特定的值(类似枚举),可辨识联合通过公共属性实现类型收窄。

常见错误

  • 错误: type Result = string | number; const result: Result = "hello"; result.toUpperCase();(直接调用字符串方法) -- 解决: 需要先收窄类型:if (typeof result === 'string') { result.toUpperCase(); }
  • 错误: type Status = "active" | "inactive"; let s: Status = "pending"; -- 解决: 只能赋值为联合类型中列出的字面量:"active" 或 "inactive"
进阶: 可辨识联合(Discriminated Union)是 TypeScript 中强大的模式,通过公共的字面量类型属性(如 status、type)实现类型安全的状态机。

枚举

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT"
}

let dir: Direction = Direction.Up;

// 数字枚举(自动递增)
enum HttpStatus {
  OK = 200,
  NotFound = 404,
  InternalError = 500
}
输出: dir 的值为 "UP",HttpStatus.OK 的值为 200
场景: 定义一组命名常量。字符串枚举需要显式赋值,数字枚举支持自动递增。枚举提高代码可读性,避免使用魔法数字或字符串。

常见错误

  • 错误: enum Color { Red, Green, Blue } let c: Color = "Red"; -- 解决: 枚举值通过枚举名访问:Color.Red,而非字符串 "Red"
  • 错误: enum Mix { A = "hello", B = 42 }(混合枚举) -- 解决: 建议统一使用字符串枚举或数字枚举,避免混用
进阶: const enum 在编译时会被内联替换,不会生成额外 JavaScript 代码,适合性能敏感场景。但 const enum 在跨模块使用时可能有兼容性问题。

泛型

TypeScript 的高级特性。本组内容涵盖泛型函数、泛型接口、泛型约束和条件类型,是编写可复用类型安全代码的关键。

泛型函数

function identity<T>(value: T): T {
  return value;
}

const num = identity<number>(42);
const str = identity("hello"); // 类型推断,无需显式指定

// 实用示例:数组工具函数
function first<T>(arr: T[]): T | undefined {
  return arr[0];
}
输出: num 类型为 number,str 类型为 string,first 返回数组第一个元素或 undefined
场景: 泛型函数允许在调用时指定类型参数,使函数可复用于多种类型,同时保持类型安全。T 是最常用的类型参数名。

常见错误

  • 错误: function identity<T>(value: T): T { return value; } const result: string = identity(42); -- 解决: 泛型会根据传入参数推断类型,identity(42) 推断 T 为 number,不能赋值给 string
  • 错误: function print<T>(value: T): void { console.log(value.length); -- 解决: T 上不能调用任意属性,需使用泛型约束限制 T 必须有 length 属性
进阶: 泛型支持多个类型参数:function map<T, U>(arr: T[], fn: (item: T) => U): U[]。默认类型参数:function createArray<T = string>(): T[]。

泛型接口

interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

interface User {
  id: number;
  name: string;
}

const userRes: ApiResponse<User> = {
  code: 200,
  message: "成功",
  data: { id: 1, name: "张三" }
};

const listRes: ApiResponse<User[]> = {
  code: 200,
  message: "成功",
  data: [{ id: 1, name: "张三" }]
};
输出: userRes.data 类型为 User,listRes.data 类型为 User[]
场景: 泛型接口使接口可复用于不同的数据类型。常见于 API 响应、容器类、工具类型等场景,data 字段的类型由泛型参数决定。

常见错误

  • 错误: const res: ApiResponse = { code: 200, message: "ok", data: null }; -- 解决: 泛型接口使用时必须指定类型参数:ApiResponse<User> 或 ApiResponse<null>
  • 错误: interface Container<T> { value: T } const c: Container = { value: 42 }; -- 解决: 指定类型参数:Container<number>,或为泛型参数设置默认值:interface Container<T = unknown>
进阶: 泛型接口支持多个类型参数和默认值:interface Map<K = string, V = unknown> { get(key: K): V; set(key: K, value: V): void; }。

泛型约束

interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(value: T): void {
  console.log(value.length);
}

logLength("hello");    // 字符串有 length
logLength([1, 2, 3]); // 数组有 length
// logLength(123);    // 数字没有 length,编译报错

// keyof 约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
输出: logLength("hello") 输出 5,logLength([1,2,3]) 输出 3,getProperty 可安全访问对象属性
场景: 使用 extends 限制泛型参数必须满足特定条件。T extends HasLength 表示 T 必须有 length 属性。keyof T 约束参数为 T 的键名。

常见错误

  • 错误: function logLength<T extends HasLength>(value: T): void { console.log(value.length); } logLength(123); -- 解决: number 类型没有 length 属性,不满足约束。传入字符串、数组等有 length 属性的值
  • 错误: function getProp<T, K>(obj: T, key: K): T[K] { -- 解决: 添加 keyof 约束:K extends keyof T,确保 K 是 T 的合法键名
进阶: new() 约束可限制泛型必须可实例化:T extends { new(): T }。泛型约束可组合:T extends A & B 表示 T 必须同时满足 A 和 B。

条件类型

// 基本条件类型
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>;  // "yes"
type B = IsString<number>;  // "no"

// 实用示例:提取 Promise 内部类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type Result = UnwrapPromise<Promise<string>>; // string

// 内置工具类型
type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;
type RequiredUser = Required<User>;
type PickUser = Pick<User, "id" | "name">;
type OmitUser = Omit<User, "email">;
输出: A 类型为 "yes",B 类型为 "no",Result 类型为 string
场景: 条件类型根据类型条件选择不同的类型结果。infer 关键字可在条件类型中推断类型。TypeScript 内置了多个基于条件类型的工具类型。

常见错误

  • 错误: type Unwrap<T> = T extends Promise<infer U> ? U : T; type R = Unwrap<string>; -- 解决: 这是正确行为,非 Promise 类型直接返回自身。如需仅处理 Promise 可加约束:T extends Promise<any>
  • 错误: type Check<T> = T extends string ? T extends number ? "both" : "string" : "other"; (嵌套条件类型过于复杂) -- 解决: 避免深层嵌套条件类型,拆分为多个命名类型别名以提高可读性
进阶: 分布式条件类型:当 T 为联合类型时,条件类型会自动分发。type ToArray<T> = T extends any ? T[] : never; ToArray<string | number> 结果为 string[] | number[]。

知识检测

学习进度

-- 已学文档
--% 知识覆盖率

学习推荐

专注模式