Skip to content

动态生成类型

类型编程的意义: 可以对已有类型做修改,可以动态生成一些类型,可以做更精准的类型检查和提示

在 TypeScript 中,动态生成类型通常是通过条件类型映射类型工具类型以及泛型等高级特性实现的。

TypeScript 本身是静态类型的,因此“动态生成类型”实际上是基于现有类型或值推导出新的类型,而不是运行时动态生成类型。

TypeScript 提供了多种方式来动态生成类型,主要依赖于其强大的类型系统(如泛型、条件类型、映射类型等)。

这些方法可以帮助我们根据已有的类型或值推导出新的类型,从而提高代码的灵活性和复用性。

需要注意的是,TypeScript 的类型系统是静态的,所有的类型推导和生成都在编译时完成,运行时无法动态生成类型。

如果需要在运行时处理动态数据结构,可以结合 TypeScript 的类型断言或类型守卫来确保类型安全。

1. 使用泛型动态生成类型

泛型允许我们在定义函数、接口或类时,使用占位符来表示类型,并在调用时指定具体的类型。

typescript
function createPair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

// 动态生成的类型为 [string, number]
const pair = createPair("hello", 42);

2. 条件类型

条件类型可以根据输入类型动态地选择输出类型。

typescript
type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

3. 映射类型

映射类型可以基于已有类型动态生成新的类型。例如,将一个对象的所有属性变为可选或只读。

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

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

type PartialUser = Partial<User>;
// 相当于:
// {
//     name?: string;
//     age?: number;
// }

4. 基于值生成类型

可以通过 typeof 操作符从运行时的值推导出类型。

typescript
const user = {
    name: "Alice",
    age: 25,
};

type UserType = typeof user;
// 相当于:
// {
//     name: string;
//     age: number;
// }

5. 模板字符串类型

TypeScript 支持基于模板字符串动态生成类型,适用于字符串拼接场景。

typescript
type EventName<T extends string> = `on${Capitalize<T>}Change`;

type ClickEvent = EventName<"click">; // "onClickChange"
type HoverEvent = EventName<"hover">; // "onHoverChange"

6. 联合类型与交叉类型

联合类型和交叉类型可以动态组合多个类型。

typescript
type UnionType = string | number;
type IntersectionType = { a: string } & { b: number };

const value: UnionType = "hello"; // 或者 42
const obj: IntersectionType = { a: "test", b: 42 };

7. 递归类型

递归类型可以动态生成复杂的嵌套结构。

typescript
type NestedArray<T> = Array<T | NestedArray<T>>;

const nested: NestedArray<number> = [1, [2, [3, 4]], 5];

8. 动态键与值

通过映射类型和条件类型,可以动态生成键值对。

typescript
type Keys = "name" | "age";

type DynamicObject<T> = {
    [K in Keys]: T;
};

type StringObject = DynamicObject<string>;
// 相当于:
// {
//     name: string;
//     age: string;
// }

9. 基于接口扩展生成类型

可以通过继承接口动态生成新的类型。

typescript
interface Base {
    id: number;
}

interface Extended extends Base {
    name: string;
}

type ExtendedType = Extended;
// 相当于:
// {
//     id: number;
//     name: string;
// }

10. infer 关键字

infer 可以用于提取类型中的部分信息,从而动态生成新类型。

typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function getUser() {
    return { name: "Alice", age: 25 };
}

type UserReturnType = ReturnType<typeof getUser>;
// 相当于:
// {
//     name: string;
//     age: number;
// }