复杂泛型类型解析
复杂泛型类型解析
TypeScript的泛型系统允许开发者创建可重用的组件,同时保持类型安全。当泛型类型开始嵌套和组合时,类型解析变得复杂但功能强大。理解这些复杂泛型类型的解析机制,能够帮助开发者构建更灵活的类型系统。
基础泛型回顾
泛型的基础形式是使用类型参数:
function identity<T>(arg: T): T {
return arg;
}
当这个函数被调用时,TypeScript会自动推断类型参数:
let output = identity<string>("hello"); // 显式指定
let output2 = identity("hello"); // 自动推断为string
泛型约束
通过extends
关键字可以约束泛型参数:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
条件类型
条件类型是泛型类型解析中的关键特性:
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
分布式条件类型
当条件类型作用于联合类型时,会进行分布式解析:
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// 解析为 string[] | number[]
类型推断infer
infer
关键字可以在条件类型中声明类型变量:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type FnReturn = ReturnType<() => number>; // number
映射类型
映射类型可以基于旧类型创建新类型:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
递归类型
TypeScript支持递归类型定义:
type JsonValue =
| string
| number
| boolean
| null
| JsonValue[]
| { [key: string]: JsonValue };
const json: JsonValue = {
name: "John",
age: 30,
hobbies: ["reading", { type: "sports", frequency: "daily" }]
};
模板字面量类型
结合泛型可以创建强大的字符串类型:
type EventName<T extends string> = `${T}Changed`;
type Concat<A extends string, B extends string> = `${A}${B}`;
type T0 = EventName<'foo'>; // 'fooChanged'
type T1 = Concat<'Hello', 'World'>; // 'HelloWorld'
复杂泛型示例解析
解析一个复杂的实用类型:
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
interface User {
id: number;
info: {
name: string;
age: number;
address: {
city: string;
country: string;
};
};
}
type PartialUser = DeepPartial<User>;
/* 等价于:
{
id?: number;
info?: {
name?: string;
age?: number;
address?: {
city?: string;
country?: string;
};
};
}
*/
类型编程技巧
结合多个高级特性创建实用类型:
type GetProps<T> =
T extends React.ComponentType<infer P> ? P : never;
type ExtractState<T> =
T extends React.Component<infer P, infer S> ? S : never;
type PromiseValue<T> =
T extends Promise<infer V> ? V : T;
类型兼容性检查
使用条件类型检查类型兼容性:
type IsAssignable<T, U> = T extends U ? true : false;
type T1 = IsAssignable<number, string | number>; // true
type T2 = IsAssignable<string, number>; // false
泛型工具类型进阶
创建更复杂的工具类型:
type Nullable<T> = T | null;
type NonNullable<T> = T extends null | undefined ? never : T;
type Flatten<T> = T extends Array<infer U> ? Flatten<U> : T;
type T3 = Flatten<number[][]>; // number
类型级编程挑战
解决实际的类型编程问题:
type Join<T extends string[], D extends string> =
T extends [] ? '' :
T extends [infer F] ? F :
T extends [infer F, ...infer R] ?
F extends string ?
R extends string[] ?
`${F}${D}${Join<R, D>}` : never : never : never;
type T4 = Join<['a', 'b', 'c'], '-'>; // 'a-b-c'
类型系统边界探索
探索TypeScript类型系统的极限:
type Fibonacci<T extends number, N1 extends number = 1, N2 extends number = 1> =
T extends 0 ? 0 :
T extends 1 | 2 ? 1 :
T extends number ? Fibonacci<Subtract<T, 1>, N2, Add<N1, N2>> : never;
// 需要定义Add和Subtract类型
type Add<A extends number, B extends number> = [...Array<A>, ...Array<B>]['length'];
type Subtract<A extends number, B extends number> =
Array<A> extends [...Array<B>, ...infer R] ? R['length'] : never;
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn