4.1 泛型编程

4.1.1 泛型基础

泛型允许我们创建可重用的组件,这些组件可以处理多种类型而不是单一类型。

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

// 使用泛型函数
let output1 = identity<string>("myString");
let output2 = identity<number>(100);

// 类型推断
let output3 = identity("myString"); // TypeScript 自动推断为 string

4.1.2 泛型约束

使用 extends 关键字来约束泛型类型:

// 基本约束
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // 现在我们知道它有 length 属性
    return arg;
}

// 使用约束
loggingIdentity("hello"); // 字符串有 length 属性
loggingIdentity([1, 2, 3]); // 数组有 length 属性
// loggingIdentity(3); // 错误:number 没有 length 属性

// 在泛型约束中使用类型参数
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

let person = { name: "Alice", age: 30, city: "New York" };
let name = getProperty(person, "name"); // string
let age = getProperty(person, "age");   // number
// let invalid = getProperty(person, "salary"); // 错误:参数类型不匹配

4.1.3 泛型类

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
    
    constructor(zeroValue: T, addFn: (x: T, y: T) => T) {
        this.zeroValue = zeroValue;
        this.add = addFn;
    }
}

// 数字版本
let myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
console.log(myGenericNumber.add(5, 10)); // 15

// 字符串版本
let myGenericString = new GenericNumber<string>("", (x, y) => x + y);
console.log(myGenericString.add("Hello ", "World")); // "Hello World"

4.1.4 泛型接口

// 泛型接口
interface GenericIdentityFn<T> {
    (arg: T): T;
}

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

let myIdentity: GenericIdentityFn<number> = identity;

// 更复杂的泛型接口
interface Repository<T> {
    findById(id: string): T | undefined;
    save(entity: T): void;
    delete(id: string): boolean;
    findAll(): T[];
}

class UserRepository implements Repository<User> {
    private users: User[] = [];
    
    findById(id: string): User | undefined {
        return this.users.find(user => user.id === id);
    }
    
    save(user: User): void {
        this.users.push(user);
    }
    
    delete(id: string): boolean {
        const index = this.users.findIndex(user => user.id === id);
        if (index > -1) {
            this.users.splice(index, 1);
            return true;
        }
        return false;
    }
    
    findAll(): User[] {
        return [...this.users];
    }
}

4.2 条件类型

4.2.1 基本条件类型

条件类型的语法:T extends U ? X : Y

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

type Test1 = IsString<string>;  // true
type Test2 = IsString<number>;  // false
type Test3 = IsString<"hello">; // true

// 更实用的例子
type NonNullable<T> = T extends null | undefined ? never : T;

type Test4 = NonNullable<string | null>;      // string
type Test5 = NonNullable<number | undefined>; // number
type Test6 = NonNullable<boolean | null | undefined>; // boolean

4.2.2 分布式条件类型

当条件类型作用于联合类型时,会分布到每个成员:

type ToArray<T> = T extends any ? T[] : never;

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

// 实用工具类型
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

type Test8 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
type Test9 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

4.2.3 条件类型中的类型推断

使用 infer 关键字在条件类型中推断类型:

// 推断返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

type Test10 = ReturnType<() => string>; // string
type Test11 = ReturnType<(x: number) => number>; // number

// 推断数组元素类型
type ArrayElementType<T> = T extends (infer U)[] ? U : never;

type Test12 = ArrayElementType<string[]>; // string
type Test13 = ArrayElementType<number[]>; // number

// 推断 Promise 的值类型
type PromiseType<T> = T extends Promise<infer U> ? U : never;

type Test14 = PromiseType<Promise<string>>; // string
type Test15 = PromiseType<Promise<number>>; // number

4.3 映射类型

4.3.1 基本映射类型

映射类型允许我们基于旧类型创建新类型:

// 基本映射类型语法
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Partial<T> = {
    [P in keyof T]?: T[P];
};

type Required<T> = {
    [P in keyof T]-?: T[P];
};

// 使用示例
interface User {
    id: string;
    name: string;
    email?: string;
}

type ReadonlyUser = Readonly<User>;
// {
//     readonly id: string;
//     readonly name: string;
//     readonly email?: string;
// }

type PartialUser = Partial<User>;
// {
//     id?: string;
//     name?: string;
//     email?: string;
// }

type RequiredUser = Required<User>;
// {
//     id: string;
//     name: string;
//     email: string; // 注意:不再是可选的
// }

4.3.2 高级映射类型

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

type UserBasicInfo = Pick<User, "id" | "name">;
// {
//     id: string;
//     name: string;
// }

// Omit:排除特定属性
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

type UserWithoutId = Omit<User, "id">;
// {
//     name: string;
//     email?: string;
// }

// Record:创建具有特定键和值类型的对象类型
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

type UserRoles = Record<"admin" | "user" | "guest", boolean>;
// {
//     admin: boolean;
//     user: boolean;
//     guest: boolean;
// }

4.3.3 键重映射

TypeScript 4.1+ 支持键重映射:

// 键重映射语法
type MappedTypeWithNewProperties<T> = {
    [Properties in keyof T as NewKeyType]: T[Properties]
}

// 示例:添加前缀
type Getters<T> = {
    [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};

type UserGetters = Getters<User>;
// {
//     getId: () => string;
//     getName: () => string;
//     getEmail: () => string | undefined;
// }

// 过滤属性
type RemoveKindField<T> = {
    [K in keyof T as K extends "kind" ? never : K]: T[K]
};

interface Circle {
    kind: "circle";
    radius: number;
}

type KindlessCircle = RemoveKindField<Circle>;
// {
//     radius: number;
// }

4.4 模板字面量类型

4.4.1 基本模板字面量类型

TypeScript 4.1+ 引入了模板字面量类型:

// 基本模板字面量类型
type World = "world";
type Greeting = `hello ${World}`; // "hello world"

// 与联合类型结合
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"

4.4.2 内置字符串操作类型

// 内置字符串操作类型
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 LoudGreeting = Uppercase<"Hello World">; // "HELLO WORLD"
type QuietGreeting = Lowercase<"Hello World">; // "hello world"
type CapitalizedGreeting = Capitalize<"hello world">; // "Hello world"
type UncapitalizedGreeting = Uncapitalize<"Hello World">; // "hello World"

// 实际应用:创建事件处理器类型
type ObjectWithOnMethods<T> = {
    [K in keyof T as `on${Capitalize<string & K>}`]: (value: T[K]) => void;
};

interface Person {
    name: string;
    age: number;
}

type PersonEventHandlers = ObjectWithOnMethods<Person>;
// {
//     onName: (value: string) => void;
//     onAge: (value: number) => void;
// }

4.4.3 模板字面量类型的实际应用

// CSS 属性类型
type CSSProperties = {
    [K in
        | "margin"
        | "padding"
        | "border" as K | `${K}Top` | `${K}Right` | `${K}Bottom` | `${K}Left`]?: string;
};

// 使用
const styles: CSSProperties = {
    margin: "10px",
    marginTop: "5px",
    padding: "20px",
    paddingLeft: "15px"
};

// API 路径类型
type APIPath<T extends string> = `/api/${T}`;
type UserAPIPath = APIPath<"users">; // "/api/users"
type ProductAPIPath = APIPath<"products">; // "/api/products"

// 数据库查询构建器
type QueryBuilder<T> = {
    [K in keyof T as `findBy${Capitalize<string & K>}`]: (value: T[K]) => T[];
};

type UserQueries = QueryBuilder<User>;
// {
//     findById: (value: string) => User[];
//     findByName: (value: string) => User[];
//     findByEmail: (value: string | undefined) => User[];
// }

4.5 实用工具类型

4.5.1 内置工具类型总结

// 基础工具类型
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 Record<K extends keyof any, T> = { [P in K]: T };

// 选择和排除
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

// 空值处理
type NonNullable<T> = T extends null | undefined ? never : T;

// 函数类型
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;

4.5.2 自定义工具类型

// 深度只读
type DeepReadonly<T> = {
    readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};

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

// 获取函数参数的第一个类型
type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never;

// 获取函数参数的尾部类型
type Tail<T extends any[]> = T extends [any, ...infer T] ? T : [];

// 判断类型是否相等
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;

// 使用示例
interface NestedUser {
    id: string;
    profile: {
        name: string;
        settings: {
            theme: string;
            notifications: boolean;
        };
    };
}

type ReadonlyNestedUser = DeepReadonly<NestedUser>;
type PartialNestedUser = DeepPartial<NestedUser>;

type FirstParam = Head<[string, number, boolean]>; // string
type RestParams = Tail<[string, number, boolean]>; // [number, boolean]

type IsEqual = Equal<string, string>; // true
type IsNotEqual = Equal<string, number>; // false

4.6 类型编程实战

4.6.1 构建类型安全的状态管理

// 状态管理类型定义
type Action<T extends string, P = {}> = {
    type: T;
} & P;

type ActionCreator<T extends string, P = {}> = P extends {} 
    ? () => Action<T, P>
    : (payload: P) => Action<T, P>;

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

type UserActions = 
    | Action<"SET_USER", { payload: User }>
    | Action<"CLEAR_USER">
    | Action<"SET_LOADING", { payload: boolean }>
    | Action<"SET_ERROR", { payload: string }>;

// 类型安全的 reducer
type Reducer<S, A> = (state: S, action: A) => S;

const userReducer: Reducer<AppState, UserActions> = (state, action) => {
    switch (action.type) {
        case "SET_USER":
            return { ...state, user: action.payload, error: null };
        case "CLEAR_USER":
            return { ...state, user: null };
        case "SET_LOADING":
            return { ...state, loading: action.payload };
        case "SET_ERROR":
            return { ...state, error: action.payload };
        default:
            return state;
    }
};

4.6.2 构建类型安全的 API 客户端

// API 端点定义
interface APIEndpoints {
    "/users": {
        GET: { response: User[] };
        POST: { body: Omit<User, "id">; 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 extends string> = 
    T extends `${infer _Start}:${infer Param}/${infer Rest}`
        ? { [K in Param]: string } & ExtractParams<`/${Rest}`>
        : T extends `${infer _Start}:${infer Param}`
        ? { [K in Param]: string }
        : {};

// API 客户端类型
type APIClient = {
    [Path in keyof APIEndpoints]: {
        [Method in keyof APIEndpoints[Path]]: (
            ...args: APIEndpoints[Path][Method] extends { params: infer P; body: infer B }
                ? [params: P, body: B]
                : APIEndpoints[Path][Method] extends { params: infer P }
                ? [params: P]
                : APIEndpoints[Path][Method] extends { body: infer B }
                ? [body: B]
                : []
        ) => Promise<APIEndpoints[Path][Method] extends { response: infer R } ? R : void>;
    };
};

// 使用示例
declare const apiClient: APIClient;

// 类型安全的 API 调用
apiClient["/users"].GET(); // Promise<User[]>
apiClient["/users"].POST({ name: "Alice", email: "alice@example.com" }); // Promise<User>
apiClient["/users/:id"].GET({ id: "123" }); // Promise<User>
apiClient["/users/:id"].PUT({ id: "123" }, { name: "Bob" }); // Promise<User>

4.7 本章练习

练习 1:泛型工具函数

实现以下泛型工具函数:

// 1. 实现一个泛型函数,用于深度克隆对象
function deepClone<T>(obj: T): T {
    // 你的实现
}

// 2. 实现一个泛型函数,用于合并两个对象
function merge<T, U>(obj1: T, obj2: U): T & U {
    // 你的实现
}

// 3. 实现一个泛型函数,用于获取对象的键值对数组
function entries<T>(obj: T): Array<[keyof T, T[keyof T]]> {
    // 你的实现
}

练习 2:高级类型操作

实现以下类型操作:

// 1. 实现一个类型,将对象的所有属性变为可选,但保持嵌套对象的结构
type DeepPartial<T> = {
    // 你的实现
};

// 2. 实现一个类型,获取对象中所有函数类型的属性名
type FunctionPropertyNames<T> = {
    // 你的实现
};

// 3. 实现一个类型,将联合类型转换为交叉类型
type UnionToIntersection<U> = {
    // 你的实现
};

练习 3:实际应用

构建一个类型安全的表单验证系统:

// 定义表单字段类型
interface FormField<T> {
    value: T;
    error?: string;
    validators: Array<(value: T) => string | undefined>;
}

// 定义表单类型
type Form<T> = {
    [K in keyof T]: FormField<T[K]>;
};

// 实现表单验证函数
function validateForm<T>(form: Form<T>): boolean {
    // 你的实现
}

// 使用示例
interface UserForm {
    name: string;
    email: string;
    age: number;
}

const userForm: Form<UserForm> = {
    // 你的实现
};

4.8 本章总结

本章深入探讨了 TypeScript 的高级类型系统,包括:

  1. 泛型编程:学习了泛型函数、泛型类、泛型接口和泛型约束
  2. 条件类型:掌握了条件类型的语法、分布式条件类型和类型推断
  3. 映射类型:了解了如何基于现有类型创建新类型,包括键重映射
  4. 模板字面量类型:学习了字符串模板类型和内置字符串操作
  5. 实用工具类型:掌握了内置工具类型和自定义工具类型的创建
  6. 类型编程实战:通过实际案例学习了高级类型系统的应用

这些高级类型特性使 TypeScript 能够提供强大的类型安全保障,同时保持代码的灵活性和可维护性。掌握这些概念对于编写高质量的 TypeScript 代码至关重要。

下一章我们将学习模块系统和命名空间,了解如何组织和管理大型 TypeScript 项目的代码结构。