TypeScript 完全指南
基础类型系统
TypeScript 是 JavaScript 的超集,提供了静态类型检查,帮助在编译时发现错误。
基本类型
| 类型 | 关键字 | 说明 | 示例 |
|---|---|---|---|
| 布尔值 | boolean | 真/假值 | let isDone: boolean = false |
| 数字 | number | 整数、浮点数、BigInt | let 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
});