主题
动态生成类型
类型编程的意义: 可以对已有类型做修改,可以动态生成一些类型,可以做更精准的类型检查和提示
在 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;
// }