typescript-advanced
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTypeScript Advanced Types
TypeScript 高级类型
Comprehensive guidance for mastering TypeScript's advanced type system including generics, conditional types, mapped types, template literal types, and utility types for building robust, type-safe applications.
本指南全面介绍如何掌握TypeScript的高级类型系统,包括泛型、条件类型、映射类型、模板字面量类型和工具类型,用于构建健壮、类型安全的应用程序。
Quick Reference
快速参考
See references/best-practices.md for practical guidelines on:
- Configuration: Essential settings (
tsconfig.json,strict,noUncheckedIndexedAccess)exactOptionalPropertyTypes - Type Inference vs Explicit Types: When to annotate vs let TypeScript infer
- Interfaces vs Types: Strategic guidelines for choosing between them
- Module/Path Mapping: tsconfig paths and barrel exports patterns
- Error Handling: Custom error classes and Result pattern
- Performance: Type system performance considerations
- Type Testing: patterns for compile-time type tests
Expect<Equal<X, Y>>
查看 references/best-practices.md 获取以下实用指南:
- 配置:必要的设置(
tsconfig.json、strict、noUncheckedIndexedAccess)exactOptionalPropertyTypes - 类型推断 vs 显式类型:何时进行类型标注 vs 让TypeScript自动推断
- 接口 vs 类型别名:选择两者的策略指南
- 模块/路径映射:tsconfig路径和桶导出模式
- 错误处理:自定义错误类和Result模式
- 性能:类型系统的性能考量
- 类型测试:用于编译时类型测试的模式
Expect<Equal<X, Y>>
When to Use This Skill
适用场景
- Building type-safe libraries or frameworks
- Creating reusable generic components
- Implementing complex type inference logic
- Designing type-safe API clients
- Building form validation systems
- Creating strongly-typed configuration objects
- Implementing type-safe state management
- Migrating JavaScript codebases to TypeScript
- 构建类型安全的库或框架
- 创建可复用的泛型组件
- 实现复杂的类型推断逻辑
- 设计类型安全的API客户端
- 构建表单验证系统
- 创建强类型的配置对象
- 实现类型安全的状态管理
- 将JavaScript代码库迁移到TypeScript
Core Concepts
核心概念
1. Generics
1. 泛型
Purpose: Create reusable, type-flexible components while maintaining type safety.
Basic Generic Function:
typescript
function identity<T>(value: T): T {
return value;
}
const num = identity<number>(42); // Type: number
const str = identity<string>("hello"); // Type: string
const auto = identity(true); // Type inferred: booleanGeneric Constraints:
typescript
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): T {
console.log(item.length);
return item;
}
logLength("hello"); // OK: string has length
logLength([1, 2, 3]); // OK: array has length
logLength({ length: 10 }); // OK: object has length
// logLength(42); // Error: number has no lengthMultiple Type Parameters:
typescript
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
const merged = merge({ name: "John" }, { age: 30 });
// Type: { name: string } & { age: number }用途:创建可复用、类型灵活的组件,同时保持类型安全。
基础泛型函数:
typescript
function identity<T>(value: T): T {
return value;
}
const num = identity<number>(42); // 类型:number
const str = identity<string>("hello"); // 类型:string
const auto = identity(true); // 自动推断类型:boolean泛型约束:
typescript
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(item: T): T {
console.log(item.length);
return item;
}
logLength("hello"); // 合法:string具有length属性
logLength([1, 2, 3]); // 合法:array具有length属性
logLength({ length: 10 }); // 合法:object具有length属性
// logLength(42); // 错误:number没有length属性多类型参数:
typescript
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}
const merged = merge({ name: "John" }, { age: 30 });
// 类型:{ name: string } & { age: number }2. Conditional Types
2. 条件类型
Purpose: Create types that depend on conditions, enabling sophisticated type logic.
Basic Conditional Type:
typescript
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // falseExtracting Return Types:
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { id: 1, name: "John" };
}
type User = ReturnType<typeof getUser>;
// Type: { id: number; name: string; }Distributive Conditional Types:
typescript
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// Type: string[] | number[]Nested Conditions:
typescript
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends undefined
? "undefined"
: T extends Function
? "function"
: "object";
type T1 = TypeName<string>; // "string"
type T2 = TypeName<() => void>; // "function"用途:创建依赖于条件的类型,实现复杂的类型逻辑。
基础条件类型:
typescript
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false提取返回类型:
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { id: 1, name: "John" };
}
type User = ReturnType<typeof getUser>;
// 类型:{ id: number; name: string; }分布式条件类型:
typescript
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// 类型:string[] | number[]嵌套条件:
typescript
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends undefined
? "undefined"
: T extends Function
? "function"
: "object";
type T1 = TypeName<string>; // "string"
type T2 = TypeName<() => void>; // "function"3. Mapped Types
3. 映射类型
Purpose: Transform existing types by iterating over their properties.
Basic Mapped Type:
typescript
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
// Type: { readonly id: number; readonly name: string; }Optional Properties:
typescript
type Partial<T> = {
[P in keyof T]?: T[P];
};
type PartialUser = Partial<User>;
// Type: { id?: number; name?: string; }Key Remapping:
typescript
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters<Person>;
// Type: { getName: () => string; getAge: () => number; }Filtering Properties:
typescript
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K];
};
interface Mixed {
id: number;
name: string;
age: number;
active: boolean;
}
type OnlyNumbers = PickByType<Mixed, number>;
// Type: { id: number; age: number; }用途:通过遍历现有类型的属性来转换类型。
基础映射类型:
typescript
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
// 类型:{ readonly id: number; readonly name: string; }可选属性:
typescript
type Partial<T> = {
[P in keyof T]?: T[P];
};
type PartialUser = Partial<User>;
// 类型:{ id?: number; name?: string; }键重映射:
typescript
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person {
name: string;
age: number;
}
type PersonGetters = Getters<Person>;
// 类型:{ getName: () => string; getAge: () => number; }属性过滤:
typescript
type PickByType<T, U> = {
[K in keyof T as T[K] extends U ? K : never]: T[K];
};
interface Mixed {
id: number;
name: string;
age: number;
active: boolean;
}
type OnlyNumbers = PickByType<Mixed, number>;
// 类型:{ id: number; age: number; }4. Template Literal Types
4. 模板字面量类型
Purpose: Create string-based types with pattern matching and transformation.
Basic Template Literal:
typescript
type EventName = "click" | "focus" | "blur";
type EventHandler = `on${Capitalize<EventName>}`;
// Type: "onClick" | "onFocus" | "onBlur"String Manipulation:
typescript
type UppercaseGreeting = Uppercase<"hello">; // "HELLO"
type LowercaseGreeting = Lowercase<"HELLO">; // "hello"
type CapitalizedName = Capitalize<"john">; // "John"
type UncapitalizedName = Uncapitalize<"John">; // "john"Path Building:
typescript
type Path<T> = T extends object
? { [K in keyof T]: K extends string ? `${K}` | `${K}.${Path<T[K]>}` : never }[keyof T]
: never;
interface Config {
server: {
host: string;
port: number;
};
database: {
url: string;
};
}
type ConfigPath = Path<Config>;
// Type: "server" | "database" | "server.host" | "server.port" | "database.url"用途:创建基于字符串的类型,支持模式匹配和转换。
基础模板字面量:
typescript
type EventName = "click" | "focus" | "blur";
type EventHandler = `on${Capitalize<EventName>}`;
// 类型:"onClick" | "onFocus" | "onBlur"字符串操作:
typescript
type UppercaseGreeting = Uppercase<"hello">; // "HELLO"
type LowercaseGreeting = Lowercase<"HELLO">; // "hello"
type CapitalizedName = Capitalize<"john">; // "John"
type UncapitalizedName = Uncapitalize<"John">; // "john"路径构建:
typescript
type Path<T> = T extends object
? { [K in keyof T]: K extends string ? `${K}` | `${K}.${Path<T[K]>}` : never }[keyof T]
: never;
interface Config {
server: {
host: string;
port: number;
};
database: {
url: string;
};
}
type ConfigPath = Path<Config>;
// 类型:"server" | "database" | "server.host" | "server.port" | "database.url"5. Utility Types
5. 工具类型
Built-in Utility Types:
typescript
// Partial<T> - Make all properties optional
type PartialUser = Partial<User>;
// Required<T> - Make all properties required
type RequiredUser = Required<PartialUser>;
// Readonly<T> - Make all properties readonly
type ReadonlyUser = Readonly<User>;
// Pick<T, K> - Select specific properties
type UserName = Pick<User, "name" | "email">;
// Omit<T, K> - Remove specific properties
type UserWithoutPassword = Omit<User, "password">;
// Exclude<T, U> - Exclude types from union
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract<T, U> - Extract types from union
type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
// NonNullable<T> - Exclude null and undefined
type T3 = NonNullable<string | null | undefined>; // string
// Record<K, T> - Create object type with keys K and values T
type PageInfo = Record<"home" | "about", { title: string }>;内置工具类型:
typescript
// Partial<T> - 将所有属性设为可选
type PartialUser = Partial<User>;
// Required<T> - 将所有属性设为必填
type RequiredUser = Required<PartialUser>;
// Readonly<T> - 将所有属性设为只读
type ReadonlyUser = Readonly<User>;
// Pick<T, K> - 选择特定属性
type UserName = Pick<User, "name" | "email">;
// Omit<T, K> - 移除特定属性
type UserWithoutPassword = Omit<User, "password">;
// Exclude<T, U> - 从联合类型中排除类型
type T1 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract<T, U> - 从联合类型中提取类型
type T2 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"
// NonNullable<T> - 排除null和undefined
type T3 = NonNullable<string | null | undefined>; // string
// Record<K, T> - 创建键为K、值为T的对象类型
type PageInfo = Record<"home" | "about", { title: string }>;Advanced Patterns
高级模式
Pattern 1: Type-Safe Event Emitter
模式1:类型安全的事件发射器
typescript
type EventMap = {
"user:created": { id: string; name: string };
"user:updated": { id: string };
"user:deleted": { id: string };
};
class TypedEventEmitter<T extends Record<string, any>> {
private listeners: {
[K in keyof T]?: Array<(data: T[K]) => void>;
} = {};
on<K extends keyof T>(event: K, callback: (data: T[K]) => void): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(callback);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
const callbacks = this.listeners[event];
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
const emitter = new TypedEventEmitter<EventMap>();
emitter.on("user:created", data => {
console.log(data.id, data.name); // Type-safe!
});
emitter.emit("user:created", { id: "1", name: "John" });
// emitter.emit("user:created", { id: "1" }); // Error: missing 'name'typescript
type EventMap = {
"user:created": { id: string; name: string };
"user:updated": { id: string };
"user:deleted": { id: string };
};
class TypedEventEmitter<T extends Record<string, any>> {
private listeners: {
[K in keyof T]?: Array<(data: T[K]) => void>;
} = {};
on<K extends keyof T>(event: K, callback: (data: T[K]) => void): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(callback);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
const callbacks = this.listeners[event];
if (callbacks) {
callbacks.forEach(callback => callback(data));
}
}
}
const emitter = new TypedEventEmitter<EventMap>();
emitter.on("user:created", data => {
console.log(data.id, data.name); // 类型安全!
});
emitter.emit("user:created", { id: "1", name: "John" });
// emitter.emit("user:created", { id: "1" }); // 错误:缺少'name'Pattern 2: Type-Safe API Client
模式2:类型安全的API客户端
typescript
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type EndpointConfig = {
"/users": {
GET: { response: User[] };
POST: { body: { name: string; email: string }; response: User };
};
"/users/:id": {
GET: { params: { id: string }; response: User };
PUT: { params: { id: string }; body: Partial<User>; response: User };
DELETE: { params: { id: string }; response: void };
};
};
type ExtractParams<T> = T extends { params: infer P } ? P : never;
type ExtractBody<T> = T extends { body: infer B } ? B : never;
type ExtractResponse<T> = T extends { response: infer R } ? R : never;
class APIClient<Config extends Record<string, Record<HTTPMethod, any>>> {
async request<Path extends keyof Config, Method extends keyof Config[Path]>(
path: Path,
method: Method,
...[options]: ExtractParams<Config[Path][Method]> extends never
? ExtractBody<Config[Path][Method]> extends never
? []
: [{ body: ExtractBody<Config[Path][Method]> }]
: [
{
params: ExtractParams<Config[Path][Method]>;
body?: ExtractBody<Config[Path][Method]>;
},
]
): Promise<ExtractResponse<Config[Path][Method]>> {
// Implementation here
return {} as any;
}
}
const api = new APIClient<EndpointConfig>();
// Type-safe API calls
const users = await api.request("/users", "GET");
// Type: User[]
const newUser = await api.request("/users", "POST", {
body: { name: "John", email: "john@example.com" },
});
// Type: User
const user = await api.request("/users/:id", "GET", {
params: { id: "123" },
});
// Type: Usertypescript
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type EndpointConfig = {
"/users": {
GET: { response: User[] };
POST: { body: { name: string; email: string }; response: User };
};
"/users/:id": {
GET: { params: { id: string }; response: User };
PUT: { params: { id: string }; body: Partial<User>; response: User };
DELETE: { params: { id: string }; response: void };
};
};
type ExtractParams<T> = T extends { params: infer P } ? P : never;
type ExtractBody<T> = T extends { body: infer B } ? B : never;
type ExtractResponse<T> = T extends { response: infer R } ? R : never;
class APIClient<Config extends Record<string, Record<HTTPMethod, any>>> {
async request<Path extends keyof Config, Method extends keyof Config[Path]>(
path: Path,
method: Method,
...[options]: ExtractParams<Config[Path][Method]> extends never
? ExtractBody<Config[Path][Method]> extends never
? []
: [{ body: ExtractBody<Config[Path][Method]> }]
: [
{
params: ExtractParams<Config[Path][Method]>;
body?: ExtractBody<Config[Path][Method]>;
},
]
): Promise<ExtractResponse<Config[Path][Method]>> {
// 实现代码
return {} as any;
}
}
const api = new APIClient<EndpointConfig>();
// 类型安全的API调用
const users = await api.request("/users", "GET");
// 类型:User[]
const newUser = await api.request("/users", "POST", {
body: { name: "John", email: "john@example.com" },
});
// 类型:User
const user = await api.request("/users/:id", "GET", {
params: { id: "123" },
});
// 类型:UserPattern 3: Builder Pattern with Type Safety
模式3:带类型安全的构建器模式
typescript
type BuilderState<T> = {
[K in keyof T]: T[K] | undefined;
};
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T];
type OptionalKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];
type IsComplete<T, S> =
RequiredKeys<T> extends keyof S ? (S[RequiredKeys<T>] extends undefined ? false : true) : false;
class Builder<T, S extends BuilderState<T> = {}> {
private state: S = {} as S;
set<K extends keyof T>(key: K, value: T[K]): Builder<T, S & Record<K, T[K]>> {
this.state[key] = value;
return this as any;
}
build(this: IsComplete<T, S> extends true ? this : never): T {
return this.state as T;
}
}
interface User {
id: string;
name: string;
email: string;
age?: number;
}
const builder = new Builder<User>();
const user = builder.set("id", "1").set("name", "John").set("email", "john@example.com").build(); // OK: all required fields set
// const incomplete = builder
// .set("id", "1")
// .build(); // Error: missing required fieldstypescript
type BuilderState<T> = {
[K in keyof T]: T[K] | undefined;
};
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T];
type OptionalKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];
type IsComplete<T, S> =
RequiredKeys<T> extends keyof S ? (S[RequiredKeys<T>] extends undefined ? false : true) : false;
class Builder<T, S extends BuilderState<T> = {}> {
private state: S = {} as S;
set<K extends keyof T>(key: K, value: T[K]): Builder<T, S & Record<K, T[K]>> {
this.state[key] = value;
return this as any;
}
build(this: IsComplete<T, S> extends true ? this : never): T {
return this.state as T;
}
}
interface User {
id: string;
name: string;
email: string;
age?: number;
}
const builder = new Builder<User>();
const user = builder.set("id", "1").set("name", "John").set("email", "john@example.com").build(); // 合法:所有必填字段已设置
// const incomplete = builder
// .set("id", "1")
// .build(); // 错误:缺少必填字段Pattern 4: Deep Readonly/Partial
模式4:深度只读/可选
typescript
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly<T[P]>
: T[P];
};
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object
? T[P] extends Array<infer U>
? Array<DeepPartial<U>>
: DeepPartial<T[P]>
: T[P];
};
interface Config {
server: {
host: string;
port: number;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
pool: {
min: number;
max: number;
};
};
}
type ReadonlyConfig = DeepReadonly<Config>;
// All nested properties are readonly
type PartialConfig = DeepPartial<Config>;
// All nested properties are optionaltypescript
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object
? T[P] extends Function
? T[P]
: DeepReadonly<T[P]>
: T[P];
};
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object
? T[P] extends Array<infer U>
? Array<DeepPartial<U>>
: DeepPartial<T[P]>
: T[P];
};
interface Config {
server: {
host: string;
port: number;
ssl: {
enabled: boolean;
cert: string;
};
};
database: {
url: string;
pool: {
min: number;
max: number;
};
};
}
type ReadonlyConfig = DeepReadonly<Config>;
// 所有嵌套属性均为只读
type PartialConfig = DeepPartial<Config>;
// 所有嵌套属性均为可选Pattern 5: Type-Safe Form Validation
模式5:类型安全的表单验证
typescript
type ValidationRule<T> = {
validate: (value: T) => boolean;
message: string;
};
type FieldValidation<T> = {
[K in keyof T]?: ValidationRule<T[K]>[];
};
type ValidationErrors<T> = {
[K in keyof T]?: string[];
};
class FormValidator<T extends Record<string, any>> {
constructor(private rules: FieldValidation<T>) {}
validate(data: T): ValidationErrors<T> | null {
const errors: ValidationErrors<T> = {};
let hasErrors = false;
for (const key in this.rules) {
const fieldRules = this.rules[key];
const value = data[key];
if (fieldRules) {
const fieldErrors: string[] = [];
for (const rule of fieldRules) {
if (!rule.validate(value)) {
fieldErrors.push(rule.message);
}
}
if (fieldErrors.length > 0) {
errors[key] = fieldErrors;
hasErrors = true;
}
}
}
return hasErrors ? errors : null;
}
}
interface LoginForm {
email: string;
password: string;
}
const validator = new FormValidator<LoginForm>({
email: [
{
validate: v => v.includes("@"),
message: "Email must contain @",
},
{
validate: v => v.length > 0,
message: "Email is required",
},
],
password: [
{
validate: v => v.length >= 8,
message: "Password must be at least 8 characters",
},
],
});
const errors = validator.validate({
email: "invalid",
password: "short",
});
// Type: { email?: string[]; password?: string[]; } | nulltypescript
type ValidationRule<T> = {
validate: (value: T) => boolean;
message: string;
};
type FieldValidation<T> = {
[K in keyof T]?: ValidationRule<T[K]>[];
};
type ValidationErrors<T> = {
[K in keyof T]?: string[];
};
class FormValidator<T extends Record<string, any>> {
constructor(private rules: FieldValidation<T>) {}
validate(data: T): ValidationErrors<T> | null {
const errors: ValidationErrors<T> = {};
let hasErrors = false;
for (const key in this.rules) {
const fieldRules = this.rules[key];
const value = data[key];
if (fieldRules) {
const fieldErrors: string[] = [];
for (const rule of fieldRules) {
if (!rule.validate(value)) {
fieldErrors.push(rule.message);
}
}
if (fieldErrors.length > 0) {
errors[key] = fieldErrors;
hasErrors = true;
}
}
}
return hasErrors ? errors : null;
}
}
interface LoginForm {
email: string;
password: string;
}
const validator = new FormValidator<LoginForm>({
email: [
{
validate: v => v.includes("@"),
message: "邮箱必须包含@",
},
{
validate: v => v.length > 0,
message: "邮箱为必填项",
},
],
password: [
{
validate: v => v.length >= 8,
message: "密码长度至少为8位",
},
],
});
const errors = validator.validate({
email: "invalid",
password: "short",
});
// 类型:{ email?: string[]; password?: string[]; } | nullPattern 6: Discriminated Unions
模式6:可辨识联合
typescript
type Success<T> = {
status: "success";
data: T;
};
type Error = {
status: "error";
error: string;
};
type Loading = {
status: "loading";
};
type AsyncState<T> = Success<T> | Error | Loading;
function handleState<T>(state: AsyncState<T>): void {
switch (state.status) {
case "success":
console.log(state.data); // Type: T
break;
case "error":
console.log(state.error); // Type: string
break;
case "loading":
console.log("Loading...");
break;
}
}
// Type-safe state machine
type State =
| { type: "idle" }
| { type: "fetching"; requestId: string }
| { type: "success"; data: any }
| { type: "error"; error: Error };
type Event =
| { type: "FETCH"; requestId: string }
| { type: "SUCCESS"; data: any }
| { type: "ERROR"; error: Error }
| { type: "RESET" };
function reducer(state: State, event: Event): State {
switch (state.type) {
case "idle":
return event.type === "FETCH" ? { type: "fetching", requestId: event.requestId } : state;
case "fetching":
if (event.type === "SUCCESS") {
return { type: "success", data: event.data };
}
if (event.type === "ERROR") {
return { type: "error", error: event.error };
}
return state;
case "success":
case "error":
return event.type === "RESET" ? { type: "idle" } : state;
}
}typescript
type Success<T> = {
status: "success";
data: T;
};
type Error = {
status: "error";
error: string;
};
type Loading = {
status: "loading";
};
type AsyncState<T> = Success<T> | Error | Loading;
function handleState<T>(state: AsyncState<T>): void {
switch (state.status) {
case "success":
console.log(state.data); // 类型:T
break;
case "error":
console.log(state.error); // 类型:string
break;
case "loading":
console.log("加载中...");
break;
}
}
// 类型安全的状态机
type State =
| { type: "idle" }
| { type: "fetching"; requestId: string }
| { type: "success"; data: any }
| { type: "error"; error: Error };
type Event =
| { type: "FETCH"; requestId: string }
| { type: "SUCCESS"; data: any }
| { type: "ERROR"; error: Error }
| { type: "RESET" };
function reducer(state: State, event: Event): State {
switch (state.type) {
case "idle":
return event.type === "FETCH" ? { type: "fetching", requestId: event.requestId } : state;
case "fetching":
if (event.type === "SUCCESS") {
return { type: "success", data: event.data };
}
if (event.type === "ERROR") {
return { type: "error", error: event.error };
}
return state;
case "success":
case "error":
return event.type === "RESET" ? { type: "idle" } : state;
}
}Type Inference Techniques
类型推断技巧
1. Infer Keyword
1. Infer关键字
typescript
// Extract array element type
type ElementType<T> = T extends (infer U)[] ? U : never;
type NumArray = number[];
type Num = ElementType<NumArray>; // number
// Extract promise type
type PromiseType<T> = T extends Promise<infer U> ? U : never;
type AsyncNum = PromiseType<Promise<number>>; // number
// Extract function parameters
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
function foo(a: string, b: number) {}
type FooParams = Parameters<typeof foo>; // [string, number]typescript
// 提取数组元素类型
type ElementType<T> = T extends (infer U)[] ? U : never;
type NumArray = number[];
type Num = ElementType<NumArray>; // number
// 提取Promise类型
type PromiseType<T> = T extends Promise<infer U> ? U : never;
type AsyncNum = PromiseType<Promise<number>>; // number
// 提取函数参数
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
function foo(a: string, b: number) {}
type FooParams = Parameters<typeof foo>; // [string, number]2. Type Guards
2. 类型守卫
typescript
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isArrayOf<T>(value: unknown, guard: (item: unknown) => item is T): value is T[] {
return Array.isArray(value) && value.every(guard);
}
const data: unknown = ["a", "b", "c"];
if (isArrayOf(data, isString)) {
data.forEach(s => s.toUpperCase()); // Type: string[]
}typescript
function isString(value: unknown): value is string {
return typeof value === "string";
}
function isArrayOf<T>(value: unknown, guard: (item: unknown) => item is T): value is T[] {
return Array.isArray(value) && value.every(guard);
}
const data: unknown = ["a", "b", "c"];
if (isArrayOf(data, isString)) {
data.forEach(s => s.toUpperCase()); // 类型:string[]
}3. Assertion Functions
3. 断言函数
typescript
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("Not a string");
}
}
function processValue(value: unknown) {
assertIsString(value);
// value is now typed as string
console.log(value.toUpperCase());
}typescript
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error("不是字符串");
}
}
function processValue(value: unknown) {
assertIsString(value);
// value现在被推断为string类型
console.log(value.toUpperCase());
}Best Practices
最佳实践
For detailed configuration and patterns, see references/best-practices.md.
有关详细的配置和模式,请查看 references/best-practices.md。
Core Guidelines
核心指南
- Use over
unknown: Enforce type checkingany - Prefer for object shapes: Better error messages, declaration merging
interface - Use for unions and complex types: More flexible for computed types
type - Leverage type inference: Let TypeScript infer when possible
- Create helper types: Build reusable type utilities
- Use const assertions: Preserve literal types
- Avoid type assertions: Use type guards instead
- Document complex types: Add JSDoc comments
- Use strict mode: Enable all strict compiler options
- Test your types: Use type tests to verify type behavior
- 使用而非
unknown:强制进行类型检查any - 优先用定义对象形状:错误信息更友好,支持声明合并
interface - 用定义联合类型和复杂类型:对计算类型更灵活
type - 利用类型推断:尽可能让TypeScript自动推断类型
- 创建辅助类型:构建可复用的类型工具
- 使用const断言:保留字面量类型
- 避免类型断言:改用类型守卫
- 为复杂类型添加文档:添加JSDoc注释
- 使用严格模式:启用所有严格编译选项
- 测试你的类型:使用类型测试验证类型行为
Type Strategy Summary
类型策略总结
| Scenario | Recommendation |
|---|---|
| Function parameters | Always explicit |
| Return types | Let TypeScript infer (usually) |
| Local variables | Let TypeScript infer |
| Public API boundaries | Always explicit |
| Object shapes (extensible) | Use |
| Union types | Use |
| Computed/mapped types | Use |
| 场景 | 推荐方案 |
|---|---|
| 函数参数 | 始终显式标注 |
| 返回类型 | 通常让TypeScript自动推断 |
| 局部变量 | 让TypeScript自动推断 |
| 公共API边界 | 始终显式标注 |
| 可扩展的对象形状 | 使用 |
| 联合类型 | 使用 |
| 计算/映射类型 | 使用 |
Recommended tsconfig.json Settings
推荐的tsconfig.json设置
json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"moduleResolution": "Bundler"
}
}json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"moduleResolution": "Bundler"
}
}Type Testing
类型测试
For detailed patterns, see references/best-practices.md.
typescript
// Type assertion tests - basic version
type AssertEqual<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
// More robust equality check (handles edge cases better)
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
? true
: false;
// Usage examples
type Test1 = Expect<Equal<string, string>>; // passes
type Test2 = Expect<Equal<string, number>>; // fails at compile time
// Test type behavior at compile time
type TestReturnType = Expect<
Equal<ReturnType<typeof myFunction>, ExpectedType>
>;
// Expect error helper
type ExpectError<T extends never> = T;
// Example usage
type ShouldError = ExpectError<AssertEqual<string, number>>;有关详细模式,请查看 references/best-practices.md。
typescript
// 类型断言测试 - 基础版本
type AssertEqual<T, U> = [T] extends [U] ? ([U] extends [T] ? true : false) : false;
// 更健壮的相等检查(更好地处理边缘情况)
type Expect<T extends true> = T;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2
? true
: false;
// 使用示例
type Test1 = Expect<Equal<string, string>>; // 通过
type Test2 = Expect<Equal<string, number>>; // 编译时失败
// 在编译时测试类型行为
type TestReturnType = Expect<
Equal<ReturnType<typeof myFunction>, ExpectedType>
>;
// 错误期望辅助工具
type ExpectError<T extends never> = T;
// 示例用法
type ShouldError = ExpectError<AssertEqual<string, number>>;Common Pitfalls
常见陷阱
- Over-using : Defeats the purpose of TypeScript
any - Ignoring strict null checks: Can lead to runtime errors
- Too complex types: Can slow down compilation
- Not using discriminated unions: Misses type narrowing opportunities
- Forgetting readonly modifiers: Allows unintended mutations
- Circular type references: Can cause compiler errors
- Not handling edge cases: Like empty arrays or null values
- 过度使用:违背TypeScript的设计初衷
any - 忽略严格空检查:可能导致运行时错误
- 类型过于复杂:会减慢编译速度
- 未使用可辨识联合:错失类型收窄的机会
- 忘记readonly修饰符:允许意外的突变
- 循环类型引用:可能导致编译器错误
- 未处理边缘情况:比如空数组或null值
Performance Considerations
性能考量
For detailed examples, see references/best-practices.md.
- Avoid deeply nested conditional types
- Use simple types when possible
- Cache complex type computations
- Limit recursion depth in recursive types
- Use build tools to skip type checking in production
- Prefer type guards over type assertions for runtime safety
- Keep union types small and simple in hot paths
有关详细示例,请查看 references/best-practices.md。
- 避免深度嵌套的条件类型
- 尽可能使用简单类型
- 缓存复杂的类型计算
- 限制递归类型的递归深度
- 使用构建工具在生产环境中跳过类型检查
- 优先使用类型守卫而非类型断言以保证运行时安全
- 在热点路径中保持联合类型小而简单
Resources
资源
- TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/
- Type Challenges: https://github.com/type-challenges/type-challenges
- TypeScript Deep Dive: https://basarat.gitbook.io/typescript/
- Effective TypeScript: Book by Dan Vanderkam
- TypeScript手册:https://www.typescriptlang.org/docs/handbook/
- Type Challenges:https://github.com/type-challenges/type-challenges
- TypeScript Deep Dive:https://basarat.gitbook.io/typescript/
- Effective TypeScript:Dan Vanderkam 所著书籍