类型提取 (Type Extraction)
类型提取是指从现有类型中提取出特定信息,如属性、方法或键等,以创建新的类型。TypeScript 提供了多种工具和操作符来帮助开发者进行类型提取,从而构建更灵活和强大的类型系统。以下是几种常见的类型提取方式及其使用场景。
1. keyof 操作符
keyof 是最常用的类型提取操作符之一,它可以从一个类型中提取出所有键的联合类型。
typescript
interface Person {
name: string;
age: number;
}
type Keys = keyof Person; // "name" | "age"2. 索引访问类型
索引访问类型允许你根据键名从类型中提取出相应的属性类型。
typescript
type NameType = Person["name"]; // string
type AgeType = Person["age"]; // number你可以结合 keyof 和索引访问类型来动态地提取属性类型:
typescript
type GetPropType<T, K extends keyof T> = T[K];
type PersonName = GetPropType<Person, "name">; // string
type PersonAge = GetPropType<Person, "age">; // number3. 映射类型
映射类型允许你基于现有类型的键创建新的类型,并可以对每个键应用转换规则。
typescript
type PartialPerson = {
[P in keyof Person]?: Person[P];
};
const partialPerson: PartialPerson = {
name: "Alice",
// age and address are optional here
};映射类型还可以用于修改属性的可选性、只读性等特性:
Partial<T>:将所有属性变为可选。Readonly<T>:将所有属性变为只读。Record<K, T>:创建一个新类型,其中键为K的联合类型,值为T。
typescript
type ReadonlyPerson = { readonly [P in keyof Person]: Person[P] };
const readonlyPerson: ReadonlyPerson = {
name: "Bob",
age: 30,
};
// readonlyPerson.name = "Charlie"; // Error: Cannot assign to 'name' because it is a read-only property.4. 条件类型
条件类型可以根据某些条件来决定返回哪种类型。这在需要根据类型特征进行分支选择时非常有用。
typescript
type IsString<T> = T extends string ? true : false;
type StringCheck = IsString<string>; // true
type NumberCheck = IsString<number>; // false条件类型也可以用来提取满足特定条件的属性:
typescript
type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
}[keyof T];
type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;
interface Part {
id: number;
getName(): string;
}
type FuncProps = FunctionProperties<Part>; // { getName: () => string }5. 模板字面量类型
模板字面量类型允许你通过字符串模板创建新的类型,这对于提取或组合字符串类型的键非常有用。
typescript
type EventConfig = {
onMouseEnter: string;
onMouseLeave: string;
};
type ExtractEventPrefix<T> = T extends `on${infer U}` ? U : never;
type EventPrefixes = ExtractEventPrefix<keyof EventConfig>; // "MouseEnter" | "MouseLeave"6. 工具类型
TypeScript 内置了一些工具类型,这些工具类型可以帮助你快速进行类型提取和转换:
Pick<T, K>:从T中选取指定的键K。Omit<T, K>:从T中移除指定的键K。Extract<T, U>:从T中提取出与U兼容的成员。Exclude<T, U>:从T中移除与U兼容的成员。
typescript
type PickPerson = Pick<Person, "name">; // { name: string }
type OmitPerson = Omit<Person, "age">; // { name: string }7. as const
as const 是一种特殊的类型断言,它允许你将一个值标记为常量,并允许 TypeScript 在编译时进行更严格的类型检查。
typescript
const keys = ["host", "port", "debug"] as const;
// 不加 as const,keys 的类型为 string[]
// 加了后,keys 的类型为 ["host", "port", "debug"]
type Keys = (typeof keys)[number];
//不加 as const,Keys 的类型为 string
//加了后,Keys 类型为 "host" | "port" | "debug"实际应用案例
假设我们有一个配置对象,希望创建一个函数来安全地更新其属性:
typescript
interface Config {
host: string;
port: number;
debug: boolean;
}
function updateConfig<K extends keyof Config>(
config: Config,
key: K,
value: Config[K]
): void {
config[key] = value;
}
const config: Config = {
host: "localhost",
port: 8080,
debug: true,
};
updateConfig(config, "host", "127.0.0.1"); // OK
updateConfig(config, "port", 9000); // OK
updateConfig(config, "debug", false); // OK
// updateConfig(config, "unknown", "value"); // Error, "unknown" is not a valid key of Config在这个例子中:
keyof Config提取了Config接口的所有键。K extends keyof Config确保了key参数只能是Config接口中的有效键。Config[K]使用索引访问类型确保value参数的类型与key对应的属性类型匹配。
总结
类型提取是 TypeScript 中一种强大的功能,它允许你从现有类型中提取出特定信息,创建新的类型,或者对现有类型进行转换。通过合理使用 keyof、索引访问类型、映射类型、条件类型、模板字面量类型以及内置工具类型,你可以构建更加健壮和灵活的类型系统,提高代码的安全性和可维护性。