基础类型系统

TypeScript 是 JavaScript 的超集,提供了静态类型检查,帮助在编译时发现错误。

基本类型

类型关键字说明示例
布尔值boolean真/假值let isDone: boolean = false
数字number整数、浮点数、BigIntlet decimal: number = 42
大整数bigint任意精度的整数let bigNumber: bigint = 9007199254740991n
字符串string文本数据let name: string = '张三'
数组T[]Array<T>相同类型的元素集合let numbers: number[] = [1, 2, 3]
元组[T, U]固定长度和类型的数组let tuple: [string, number] = ['年龄', 25]
枚举enum一组命名的常量enum Color { Red, Green, Blue }
任意类型any任意类型(尽量避免)let anyValue: any = '可以是任何类型'
未知类型unknown安全的 any,需类型收窄let unknownValue: unknown = '值'
空类型void没有返回值function log(): void { }
空值null空对象引用let n: null = null
未定义undefined未初始化的值let u: undefined = undefined
永不类型never永远不会出现的值function error(): never { throw new Error() }
// 布尔值
let isDone: boolean = false;
let isValid: boolean = true;

// 数字(支持整数、浮点数、BigInt)
let decimal: number = 42;
let hex: number = 0xff; // 十六进制
let binary: number = 0b1010; // 二进制
let octal: number = 0o744; // 八进制
let bigNumber: bigint = 9007199254740991n;

// 字符串
let name: string = '张三';
let greeting: string = `你好, ${name}`; // 模板字符串

// 数组
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: Array<string> = ['a', 'b', 'c']; // 泛型语法

// 元组(固定长度和类型的数组)
let tuple: [string, number] = ['年龄', 25];
let [label, value] = tuple; // 解构

// 枚举
enum Color {
  Red,    // 0
  Green,  // 1
  Blue    // 2
}
let color: Color = Color.Green;

// 带值的枚举
enum StatusCode {
  Success = 200,
  NotFound = 404,
  Error = 500
}
let status: StatusCode = StatusCode.Success;

// 字符串枚举
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}

// any(任意类型,尽量避免)
let anyValue: any = '可以是任何类型';
anyValue = 123;
anyValue = true;

// unknown(安全的 any)
let unknownValue: unknown = '也是任何类型';
// unknownValue.toFixed(); // 错误:需要先进行类型检查

if (typeof unknownValue === 'string') {
  console.log(unknownValue.toUpperCase()); // 类型收窄
}

// void(没有返回值)
function logMessage(): void {
  console.log('这条消息没有返回值');
}

// null 和 undefined
let n: null = null;
let u: undefined = undefined;

// never(永远不会出现的值)
function error(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {
    // 永远不会结束
  }
}

类型注解与类型推断

// 显式类型注解
let username: string = '张三';
let age: number = 25;

// 类型推断(TypeScript 自动推断类型)
let inferredString = '自动推断为 string'; // string
let inferredNumber = 42; // number
let inferredBoolean = true; // boolean

// 函数返回类型推断
function add(a: number, b: number): number {
  return a + b; // 自动推断返回类型为 number
}

// 建议:对于复杂函数,显式声明返回类型
function calculateTotal(items: Array<{ price: number; quantity: number }>): number {
  return items.reduce((total, item) => total + item.price * item.quantity, 0);
}

// 上下文类型推断
document.addEventListener('click', (event) => {
  // event 自动推断为 MouseEvent
  console.log(event.clientX, event.clientY);
});

对象与接口

interface 接口

接口用于定义对象的结构,是 TypeScript 中最常用的类型定义方式。

// 基本接口
interface User {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
}

const user1: User = {
  id: 1,
  name: '张三',
  email: 'zhangsan@example.com',
  isActive: true
};

// 可选属性
interface Product {
  id: number;
  name: string;
  description?: string; // 可选
  price: number;
  tags?: string[]; // 可选
}

const product1: Product = {
  id: 1,
  name: '商品A',
  price: 99.99
};

const product2: Product = {
  id: 2,
  name: '商品B',
  description: '这是一个商品',
  price: 199.99,
  tags: ['热销', '推荐']
};

// 只读属性
interface Config {
  readonly apiKey: string;
  readonly baseUrl: string;
  timeout: number;
}

const config: Config = {
  apiKey: 'abc123',
  baseUrl: 'https://api.example.com',
  timeout: 5000
};

// config.apiKey = 'newkey'; // 错误:不能修改只读属性

// 索引签名
interface Dictionary {
  [key: string]: string; // 键为字符串,值为字符串
}

const dict: Dictionary = {
  hello: '你好',
  world: '世界'
};

// 数字索引
interface StringArray {
  [index: number]: string;
}

const arr: StringArray = ['a', 'b', 'c'];

// 接口继承
interface BasicUser {
  id: number;
  name: string;
}

interface UserWith extends BasicUser {
  email: string;
  age: number;
}

const user2: UserWith = {
  id: 2,
  name: '李四',
  email: 'lisi@example.com',
  age: 30
};

// 多重继承
interface Timestamped {
  createdAt: Date;
  updatedAt: Date;
}

interface Audited {
  createdBy: string;
  updatedBy: string;
}

interface Document extends BasicUser, Timestamped, Audited {
  title: string;
  content: string;
}

// 函数类型接口
interface MathFunction {
  (a: number, b: number): number;
}

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

// 混合类型接口(既有属性又有方法)
interface Counter {
  (start: number): number; // 可调用
  interval: number; // 属性
  reset(): void; // 方法
}

// 类实现接口
interface Printable {
  print(): void;
}

interface Loggable {
  log(): void;
}

class Report implements Printable, Loggable {
  constructor(private data: string) {}
  
  print() {
    console.log(`Report: ${this.data}`);
  }
  
  log() {
    console.log(`Logging: ${this.data}`);
  }
}

type 类型别名

类型别名可以给一个类型起一个新名字,可以表示任何类型。

// 基本类型别名
type ID = string | number;
type Callback<T> = (data: T) => void;
type Point = {
  x: number;
  y: number;
};

const userId1: ID = 123;
const userId2: ID = 'abc';

const point: Point = { x: 10, y: 20 };

// 联合类型
type Status = 'pending' | 'processing' | 'completed' | 'failed';
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';

let currentStatus: Status = 'pending';
let method: HttpMethod = 'GET';

// 交叉类型
type HasName = { name: string };
type HasAge = { age: number };
type HasEmail = { email: string };

type Person = HasName & HasAge & HasEmail;

const person: Person = {
  name: '张三',
  age: 25,
  email: 'zhangsan@example.com'
};

// 字面量类型
type Direction = 'up' | 'down' | 'left' | 'right';
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;

function move(direction: Direction) {
  console.log(`Moving ${direction}`);
}

move('up'); // 正确
// move('forward'); // 错误

// 元组类型
type Coordinate = [number, number];
type RGB = [number, number, number];
type RGBA = [number, number, number, number];

const coord: Coordinate = [10, 20];
const color: RGB = [255, 128, 0];
const colorWithAlpha: RGBA = [255, 128, 0, 0.5];

// 可选元组(TypeScript 4.0+)
type OptionalTuple = [string, number?];

const tuple1: OptionalTuple = ['hello', 42];
const tuple2: OptionalTuple = ['hello'];

// 只读元组
type ReadonlyTuple = readonly [string, number];

const tuple3: ReadonlyTuple = ['test', 123];
// tuple3[0] = 'new'; // 错误:不能修改

泛型 (Generics)

泛型允许我们创建可重用的组件,能够与多种类型一起工作,同时保持类型安全。

// 泛型函数
function identity<T>(arg: T): T {
  return arg;
}

const num = identity<number>(42); // 明确指定类型
const str = identity('hello'); // 自动推断为 string

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

const p = pair<string, number>('年龄', 25); // [string, number]

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

function logLength<T extends HasLength>(arg: T): T {
  console.log(`长度: ${arg.length}`);
  return arg;
}

logLength('hello'); // 字符串有 length 属性
logLength([1, 2, 3]); // 数组有 length 属性
logLength({ length: 10, name: 'test' }); // 对象有 length 属性
// logLength(123); // 错误:数字没有 length 属性

// 泛型接口
interface ApiResponse<T> {
  code: number;
  message: string;
  data: T;
}

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

interface Product {
  id: number;
  name: string;
  price: number;
}

const userResponse: ApiResponse<User> = {
  code: 200,
  message: '成功',
  data: {
    id: 1,
    name: '张三',
    email: 'zhangsan@example.com'
  }
};

const productsResponse: ApiResponse<Product[]> = {
  code: 200,
  message: '成功',
  data: [
    { id: 1, name: '商品A', price: 99.99 },
    { id: 2, name: '商品B', price: 199.99 }
  ]
};

// 泛型类
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];
  }
  
  isEmpty(): boolean {
    return this.items.length === 0;
  }
  
  size(): number {
    return this.items.length;
  }
}

const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
console.log(numberStack.pop()); // 3
console.log(numberStack.peek()); // 2

const stringStack = new Stack<string>();
stringStack.push('hello');
stringStack.push('world');

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

const user = { name: '张三', age: 25, email: 'zhangsan@example.com' };

const nameValue = getProperty(user, 'name'); // string
const ageValue = getProperty(user, 'age'); // number
// const invalid = getProperty(user, 'invalid'); // 错误

// 泛型工具函数
function merge<T extends object, U extends object>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

const merged = merge(
  { name: '张三' },
  { age: 25 }
); // { name: string } & { age: number }

// 泛型工厂函数
function createFactory<T>(constructor: new (...args: any[]) => T) {
  return (...args: ConstructorParameters<typeof constructor>): T => {
    return new constructor(...args);
  };
}

class Person {
  constructor(public name: string, public age: number) {}
}

const createPerson = createFactory(Person);
const person = createPerson('李四', 30);

实用工具类型

TypeScript 提供了许多内置的工具类型,可以方便地进行类型转换。

// 假设我们有这个接口
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
  address?: string;
}

// Partial<T> - 所有属性变为可选
type PartialUser = Partial<User>;
// 等价于:
// {
//   id?: number;
//   name?: string;
//   email?: string;
//   age?: number;
//   address?: string;
// }

// 使用场景:更新函数
function updateUser(id: number, updates: Partial<User>): Promise<User> {
  // 只更新提供的字段
  return fetch(`/api/users/${id}`, {
    method: 'PATCH',
    body: JSON.stringify(updates)
  }).then(res => res.json());
}

updateUser(1, { name: '新名字' }); // 只更新 name
updateUser(1, { email: 'new@example.com', age: 26 }); // 更新多个字段

// Required<T> - 所有属性变为必需
type RequiredUser = Required<User>;
// 等价于:
// {
//   id: number;
//   name: string;
//   email: string;
//   age: number;
//   address: string; // address 现在是必需的
// }

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

const readonlyUser: ReadonlyUser = {
  id: 1,
  name: '张三',
  email: 'zhangsan@example.com',
  age: 25
};

// readonlyUser.name = '李四'; // 错误:不能修改只读属性

// Pick<T, K> - 从 T 中选取部分属性 K
type UserBasicInfo = Pick<User, 'id' | 'name'>;
// 等价于:
// {
//   id: number;
//   name: string;
// }

// 使用场景:列表展示
function displayUsers(users: UserBasicInfo[]) {
  users.forEach(user => {
    console.log(`${user.id}: ${user.name}`);
  });
}

// Omit<T, K> - 从 T 中省略部分属性 K
type UserWithoutEmail = Omit<User, 'email' | 'address'>;
// 等价于:
// {
//   id: number;
//   name: string;
//   age: number;
// }

// Record<K, T> - 创建一个对象类型,键为 K,值为 T
type UserRoles = Record<'admin' | 'editor' | 'viewer', string[]>;
// 等价于:
// {
//   admin: string[];
//   editor: string[];
//   viewer: string[];
// }

const roles: UserRoles = {
  admin: ['张三', '李四'],
  editor: ['王五'],
  viewer: ['赵六', '孙七']
};

// 数字键的 Record
type UserById = Record<number, User>;

const userMap: UserById = {
  1: { id: 1, name: '张三', email: 'zhangsan@example.com', age: 25 },
  2: { id: 2, name: '李四', email: 'lisi@example.com', age: 30 }
};

// ReturnType<T> - 获取函数的返回类型
function fetchUser(): Promise<User> {
  return Promise.resolve({
    id: 1,
    name: '张三',
    email: 'zhangsan@example.com',
    age: 25
  });
}

type UserReturnType = ReturnType<typeof fetchUser>;
// Promise<User>

type UserResolvedType = Awaited<UserReturnType>;
// User (TypeScript 4.5+)

// Parameters<T> - 获取函数的参数类型(元组)
function createUser(name: string, age: number, email?: string): User {
  return {
    id: Date.now(),
    name,
    age,
    email: email || '',
  };
}

type CreateUserParams = Parameters<typeof createUser>;
// [name: string, age: number, email?: string]

// 使用场景
const params: CreateUserParams = ['张三', 25, 'zhangsan@example.com'];
const newUser = createUser(...params);

// ConstructorParameters<T> - 获取构造函数的参数类型
class UserController {
  constructor(private userService: any, private logger: any) {}
}

type UserControllerParams = ConstructorParameters<typeof UserController>;
// [userService: any, logger: any]

// InstanceType<T> - 获取类的实例类型
type UserControllerInstance = InstanceType<typeof UserController>;

// Exclude<T, U> - 从 T 中排除可赋值给 U 的类型
type T1 = Exclude<'a' | 'b' | 'c', 'a' | 'c'>; // 'b'
type T2 = Exclude<string | number | boolean, string>; // number | boolean

// Extract<T, U> - 从 T 中提取可赋值给 U 的类型
type T3 = Extract<'a' | 'b' | 'c', 'a' | 'c'>; // 'a' | 'c'
type T4 = Extract<string | number | boolean, string>; // string

// NonNullable<T> - 从 T 中排除 null 和 undefined
type T5 = NonNullable<string | number | null | undefined>;
// string | number

// 实际应用:API 响应处理
interface ApiResponse<T> {
  data: T | null;
  error: string | null;
  loading: boolean;
}

type UserData = NonNullable<ApiResponse<User>['data']>;
// User

// ThisType<T> - 标记 this 的类型(用于对象字面量方法)
interface Point {
  x: number;
  y: number;
  move(dx: number, dy: number): void;
}

const point = {
  x: 0,
  y: 0,
  move(this: Point, dx: number, dy: number) {
    this.x += dx;
    this.y += dy;
  }
};

高级类型

条件类型

条件类型根据条件表达式选择类型。

// 基本语法:T extends U ? X : Y
type IsString<T> = T extends string ? true : false;

type T1 = IsString<string>; // true
type T2 = IsString<number>; // false

// 条件类型分发
type ToArray<T> = T extends any ? T[] : never;

type T3 = ToArray<string | number>; // string[] | number[]

// 如果不希望分发,使用 [T]
type ToArrayNoDistribute<T> = [T] extends [any] ? T[] : never;

type T4 = ToArrayNoDistribute<string | number>; // (string | number)[]

// 实际应用:提取 Promise 的类型
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type T5 = UnwrapPromise<Promise<string>>; // string
type T6 = UnwrapPromise<number>; // number

// infer 关键字:在条件类型中推断类型变量
type ReturnType2<T> = T extends (...args: any[]) => infer R ? R : any;

type T7 = ReturnType2<() => string>; // string
type T8 = ReturnType2<(x: number) => boolean>; // boolean

// 提取函数的第一个参数类型
type FirstParameter<T> = T extends (first: infer P, ...args: any[]) => any ? P : never;

type T9 = FirstParameter<(x: string, y: number) => void>; // string

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

type T10 = ElementType<string[]>; // string
type T11 = ElementType<number[]>; // number

// 递归条件类型
type DeepPartial<T> = T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T;

interface ComplexObject {
  user: {
    name: string;
    address: {
      city: string;
      zip: string;
    };
  };
  items: Array<{
    id: number;
    name: string;
  }>;
}

type DeepPartialComplex = DeepPartial<ComplexObject>;
// 所有嵌套属性都变为可选

// 映射类型修饰符
type Mutable<T> = {
  -readonly [P in keyof T]: T[P]; // 移除 readonly
};

type Required2<T> = {
  [P in keyof T]-?: T[P]; // 移除可选
};

模板字面量类型

TypeScript 4.1+ 支持模板字面量类型。

// 基本用法
type Greeting = `Hello, ${string}`;

const g1: Greeting = 'Hello, 张三'; // 正确
// const g2: Greeting = 'Hi, 张三'; // 错误

// 联合类型分发
type Color = 'red' | 'green' | 'blue';
type ColorSelector = `.${Color}-selector`;
// '.red-selector' | '.green-selector' | '.blue-selector'

// 字符串操作类型
type Uppercase<S extends string> = intrinsic; // 内置
type Lowercase<S extends string> = intrinsic;
type Capitalize<S extends string> = intrinsic;
type Uncapitalize<S extends string> = intrinsic;

type T1 = Uppercase<'hello'>; // 'HELLO'
type T2 = Lowercase<'HELLO'>; // 'hello'
type T3 = Capitalize<'hello'>; // 'Hello'
type T4 = Uncapitalize<'Hello'>; // 'hello'

// 实际应用:CSS 类名
type CSSProperty = 'color' | 'background' | 'border';
type CSSModifier = 'hover' | 'focus' | 'active';

type CSSClass = `-${CSSProperty}-${CSSModifier}`;
// '-color-hover' | '-color-focus' | '-color-active' | '-background-hover' | ...

// 事件处理
type EventName = 'click' | 'focus' | 'blur' | 'submit';
type EventHandler = `on${Capitalize<EventName>}`;
// 'onClick' | 'onFocus' | 'onBlur' | 'onSubmit'

// 路径类型
type PathSegment = 'users' | 'posts' | 'comments';
type APIPath = `/api/${PathSegment}`;
// '/api/users' | '/api/posts' | '/api/comments'

实战示例

类型安全的 API 客户端

// 定义 API 端点类型
interface ApiEndpoints {
  '/users': {
    GET: { response: User[] };
    POST: { request: Omit<User, 'id'>; response: User };
  };
  '/users/:id': {
    GET: { response: User };
    PUT: { request: Partial<User>; response: User };
    DELETE: { response: void };
  };
  '/posts': {
    GET: { response: Post[] };
    POST: { request: Omit<Post, 'id'>; response: Post };
  };
}

// 类型安全的请求函数
async function apiCall<
  Path extends keyof ApiEndpoints,
  Method extends keyof ApiEndpoints[Path]
>(
  path: Path,
  method: Method,
  body?: ApiEndpoints[Path][Method] extends { request: any }
    ? ApiEndpoints[Path][Method]['request']
    : never
): Promise<ApiEndpoints[Path][Method] extends { response: infer R } ? R : never> {
  const response = await fetch(path as string, {
    method: method as string,
    body: body ? JSON.stringify(body) : undefined
  });
  
  return response.json();
}

// 使用
const users = await apiCall('/users', 'GET');
// 自动推断为 User[]

const newUser = await apiCall('/users', 'POST', {
  name: '张三',
  email: 'zhangsan@example.com',
  age: 25
});
// 自动推断为 User

类型安全的状态管理

// 定义状态和动作
interface AppState {
  user: User | null;
  posts: Post[];
  loading: boolean;
  error: string | null;
}

type Action =
  | { type: 'SET_USER'; payload: User }
  | { type: 'CLEAR_USER' }
  | { type: 'ADD_POST'; payload: Post }
  | { type: 'SET_LOADING'; payload: boolean }
  | { type: 'SET_ERROR'; payload: string | null };

// 类型安全的 reducer
function reducer(state: AppState, action: Action): AppState {
  switch (action.type) {
    case 'SET_USER':
      return { ...state, user: action.payload };
    
    case 'CLEAR_USER':
      return { ...state, user: null };
    
    case 'ADD_POST':
      return { ...state, posts: [...state.posts, action.payload] };
    
    case 'SET_LOADING':
      return { ...state, loading: action.payload };
    
    case 'SET_ERROR':
      return { ...state, error: action.payload };
    
    default:
      return state;
  }
}

// 类型安全的 store
class Store<T> {
  private state: T;
  private listeners: Array<(state: T) => void> = [];
  
  constructor(initialState: T) {
    this.state = initialState;
  }
  
  getState(): T {
    return this.state;
  }
  
  setState(updater: (state: T) => T): void {
    this.state = updater(this.state);
    this.listeners.forEach(listener => listener(this.state));
  }
  
  subscribe(listener: (state: T) => void): () => void {
    this.listeners.push(listener);
    return () => {
      this.listeners = this.listeners.filter(l => l !== listener);
    };
  }
}

const store = new Store<AppState>({
  user: null,
  posts: [],
  loading: false,
  error: null
});