在TypeScript中,类型转换(Type Transformation)是一个强大的功能,可以通过不同的方法将一种类型转换成另一种类型。以下是一些高级类型转换的示例:
1. 映射类型(Mapped Types)
映射类型可以通过在现有类型的基础上创建一个新类型。
type Person = {
name: string;
age: number;
};
// 将所有属性设为可选
type PartialPerson = {
[P in keyof Person]?: Person[P];
};
// 将所有属性设为只读
type ReadonlyPerson = {
readonly [P in keyof Person]: Person[P];
};
2. 条件类型(Conditional Types)
条件类型允许你根据条件生成不同的类型。
type IsString<T> = T extends string ? 'yes' : 'no';
type Test1 = IsString<string>; // 'yes'
type Test2 = IsString<number>; // 'no'
3. 提取和排除类型(Extract and Exclude)
Extract
和Exclude
用于从联合类型中提取或排除子类型。
type Union = string | number | boolean;
// 提取字符串和数字类型
type StringOrNumber = Extract<Union, string | number>; // string | number
// 排除布尔类型
type NotBoolean = Exclude<Union, boolean>; // string | number
4. 内置的类型工具(Utility Types)
TypeScript 提供了一些内置的类型工具来简化常见的类型转换。
type Person = {
name: string;
age: number;
address?: string;
};
// 将所有属性设为可选
type PartialPerson = Partial<Person>;
// 将所有属性设为只读
type ReadonlyPerson = Readonly<Person>;
// 从类型中选取部分属性
type NameAndAge = Pick<Person, 'name' | 'age'>;
// 排除某些属性
type AddresslessPerson = Omit<Person, 'address'>;
5. 索引类型查询和访问(Index Types)
索引类型查询和访问允许你动态地获取和操作类型中的属性。
type Person = {
name: string;
age: number;
};
// 获取属性类型
type NameType = Person['name']; // string
// 动态获取属性类型
type PropertyType<T, K extends keyof T> = T[K];
type AgeType = PropertyType<Person, 'age'>; // number
6. 映射联合类型(Mapped Union Types)
通过映射联合类型,可以创建更复杂的类型转换。
type Status = 'success' | 'error' | 'loading';
type StatusMessages = {
[K in Status]: K extends 'success' ? 'Operation was successful' :
K extends 'error' ? 'There was an error' :
'Loading...';
};
// StatusMessages 的类型
// {
// success: 'Operation was successful',
// error: 'There was an error',
// loading: 'Loading...'
// }
7. 递归类型(Recursive Types)
递归类型允许你定义自引用的类型。
type Tree<T> = {
value: T;
children?: Tree<T>[];
};
const tree: Tree<string> = {
value: 'root',
children: [
{ value: 'child1' },
{ value: 'child2', children: [{ value: 'grandchild1' }] }
]
};
8. 交叉类型(Intersection Types)
交叉类型可以将多个类型合并为一个类型。
type A = { a: number };
type B = { b: string };
type C = A & B;
const c: C = { a: 1, b: 'hello' };
这些高级类型转换技巧可以帮助你在TypeScript中创建更灵活和强大的类型定义。
9. 类型推断(Type Inference)
在条件类型中可以使用 infer
关键字进行类型推断。
type ElementType<T> = T extends (infer U)[] ? U : T;
type StringType = ElementType<string[]>; // string
type NumberType = ElementType<number>; // number
10. 分布式条件类型(Distributive Conditional Types)
条件类型默认在联合类型上是分布式的。
type ToArray<T> = T extends any ? T[] : never;
type StringArray = ToArray<string>; // string[]
type NumberArray = ToArray<number>; // number[]
type UnionArray = ToArray<string | number>; // string[] | number[]
11. 元组与数组转换(Tuple and Array Transformation)
你可以通过条件类型和映射类型在元组和数组之间进行转换。
type TupleToUnion<T> = T extends (infer U)[] ? U : never;
type UnionFromTuple = TupleToUnion<[string, number, boolean]>; // string | number | boolean
type ArrayToTuple<T extends any[]> = { [K in keyof T]: T[K] };
type TupleType = ArrayToTuple<[string, number, boolean]>; // [string, number, boolean]
12. 条件类型中的类型推断
通过 infer
可以在条件类型中推断类型的一部分。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Func = () => string;
type FuncReturnType = ReturnType<Func>; // string
13. 模式匹配与提取(Pattern Matching and Extraction)
在条件类型中,可以通过模式匹配提取出类型的一部分。
type GetFirstArgType<T> = T extends (arg1: infer U, ...args: any[]) => any ? U : never;
type FunctionType = (arg1: string, arg2: number) => void;
type FirstArgType = GetFirstArgType<FunctionType>; // string
14. 推断元组长度(Infer Tuple Length)
可以通过递归条件类型推断元组的长度。
type LengthOfTuple<T extends any[], L extends any[] = []> = T extends [infer First, ...infer Rest]
? LengthOfTuple<Rest, [First, ...L]>
: L['length'];
type Length = LengthOfTuple<[string, number, boolean]>; // 3
15. 递归类型与类型运算(Recursive Types and Type Operations)
你可以通过递归类型和类型运算实现复杂的类型变换。
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
type NestedObject = {
a: {
b: {
c: string;
};
};
};
type ReadonlyNestedObject = DeepReadonly<NestedObject>;
// {
// readonly a: {
// readonly b: {
// readonly c: string;
// };
// };
// }
16. 类型守卫(Type Guards)
类型守卫用于在运行时判断类型,并在编译时进行类型缩小。
function isString(value: any): value is string {
return typeof value === 'string';
}
function example(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()); // 在此分支中,value 被推断为 string
} else {
console.log(value.toFixed()); // 在此分支中,value 被推断为 number
}
}
17. 高级泛型用法(Advanced Generics)
通过泛型实现更灵活的类型。
type Filter<T, U> = T extends U ? T : never;
type NumbersOnly = Filter<string | number | boolean, number>; // number
type NonNullable<T> = T extends null | undefined ? never : T;
type NonNullableType = NonNullable<string | number | null | undefined>; // string | number
18. 联合类型分布式条件(Distributive Conditional Types)
在联合类型上使用条件类型会自动进行分布计算,这是 TypeScript 类型系统的一大特性。
type NonNullable<T> = T extends null | undefined ? never : T;
type Result = NonNullable<string | number | undefined>; // string | number
19. 模板字面量类型(Template Literal Types)
模板字面量类型允许你基于字符串模板生成新的类型。
type EventName<T extends string> = `${T}Changed`;
type ClickEvent = EventName<'click'>; // "clickChanged"
type FocusEvent = EventName<'focus'>; // "focusChanged"
20. 映射元组类型(Mapped Tuple Types)
可以对元组类型进行映射,从而生成新的元组类型。
type MapToPromise<T> = {
[P in keyof T]: Promise<T[P]>;
};
type Tuple = [number, string, boolean];
type PromiseTuple = MapToPromise<Tuple>; // [Promise<number>, Promise<string>, Promise<boolean>]
21. 符合键类型(Compound Key Types)
可以组合多个键来生成新的类型。
type NestedKeys<T> = {
[K in keyof T]: T[K] extends object ? `${K & string}.${NestedKeys<T[K]>}` : K & string
}[keyof T];
type Person = {
name: string;
address: {
street: string;
city: string;
};
};
type Keys = NestedKeys<Person>; // "name" | "address.street" | "address.city"
22. 联合类型的差集(Difference of Union Types)
计算两个联合类型之间的差集。
type Diff<T, U> = T extends U ? never : T;
type A = 'a' | 'b' | 'c';
type B = 'b' | 'c' | 'd';
type Difference = Diff<A, B>; // "a"
23. 组合条件类型(Combination of Conditional Types)
组合条件类型可以实现复杂的类型逻辑。
type IsNever<T> = [T] extends [never] ? true : false;
type IsUnion<T> = T extends any ? ([T] extends [T] ? false : true) : never;
type TestNever = IsNever<never>; // true
type TestUnion = IsUnion<string | number>; // true
type TestNonUnion = IsUnion<string>; // false
24. 索引签名(Index Signatures)
索引签名允许你定义具有动态键的对象类型。
type Dictionary<T> = {
[key: string]: T;
};
type StringDictionary = Dictionary<string>;
const example: StringDictionary = {
key1: "value1",
key2: "value2"
};
25. 类型保护(Type Guards)
类型保护用于在代码中进行类型的缩小,从而在特定代码块中得到更准确的类型。
function isNumber(value: any): value is number {
return typeof value === 'number';
}
function example(value: string | number) {
if (isNumber(value)) {
console.log(value.toFixed()); // value 被推断为 number
} else {
console.log(value.toUpperCase()); // value 被推断为 string
}
}
26. 索引访问类型(Indexed Access Types)
索引访问类型允许你从对象类型中提取某个属性的类型。
type Person = {
name: string;
age: number;
};
type NameType = Person['name']; // string
type AgeType = Person['age']; // number
27. 类型别名(Type Aliases)
类型别名允许你为复杂的类型定义一个简短的名字。
type Point = {
x: number;
y: number;
};
type Point3D = Point & {
z: number;
};
const point: Point3D = { x: 1, y: 2, z: 3 };
28. 泛型约束(Generic Constraints)
泛型约束允许你对泛型参数进行限制。
function identity<T extends number | string>(value: T): T {
return value;
}
const num = identity(42); // 42
const str = identity("Hello"); // "Hello"
29. 高阶类型(Higher-order Types)
高阶类型是指接受类型参数并返回新类型的类型。
type WithId<T> = T & { id: string };
type User = {
name: string;
age: number;
};
type UserWithId = WithId<User>; // { name: string; age: number; id: string }
30. 构造签名(Constructor Signatures)
构造签名用于定义类的构造函数类型。
interface Constructable<T> {
new (...args: any[]): T;
}
class Person {
constructor(public name: string) {}
}
function createInstance<T>(ctor: Constructable<T>, ...args: any[]): T {
return new ctor(...args);
}
const person = createInstance(Person, 'John'); // Person { name: 'John' }
这些高级用法展示了 TypeScript 类型系统的强大和灵活性。通过这些技巧,你可以在项目中实现更强的类型安全和更好的代码提示。