MapTypes
挑战
实现类型 MapTypes<T, R>
,将对象 T
中的类型转换成由类型 R
定义的类型,其结
构如下:
type StringToNumber = {
mapFrom: string; // value of key which value is string
mapTo: number; // will be transformed for number
};
例如:
type StringToNumber = { mapFrom: string; mapTo: number };
MapTypes<{ iWillBeANumberOneDay: string }, StringToNumber>; // gives { iWillBeANumberOneDay: number; }
注意用户可能提供类型的联合:
type StringToNumber = { mapFrom: string; mapTo: number };
type StringToDate = { mapFrom: string; mapTo: Date };
MapTypes<{ iWillBeNumberOrDate: string }, StringToDate | StringToNumber>; // gives { iWillBeNumberOrDate: number | Date; }
如果该类型在映射中不存在,则保持原样:
type StringToNumber = { mapFrom: string; mapTo: number };
MapTypes<
{ iWillBeANumberOneDay: string; iWillStayTheSame: Function },
StringToNumber
>; // // gives { iWillBeANumberOneDay: number, iWillStayTheSame: Function }
解答
在这个挑战中,我们需要使用对象映射类型。我们需要枚举对象并将值类型从一个类型映射 到另一个。
让我们先从实现空白类型开始:
type MapTypes<T, R> = any;
类型参数 T
是我们需要去映射的对象, 参数 R
表示其映射关系。我们先给映射类型
参数 R
增加泛型限制:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = any;
在实际进行映射之前,我们先从简单的映射类型复制输入类型 T
开始:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P];
};
现在,在“复制”对象类型的基础上,我们可以开始添加一些映射。根据挑战要求,首先我们
先检查值类型是否与 mapFrom
类型匹配:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P] extends R["mapFrom"] ? never : never;
};
在这种情况下我们有一个匹配,这意味着我们需要用 mapTo
的类型替换当前值类型:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P] extends R["mapFrom"] ? R["mapTo"] : never;
};
否则,如果没有匹配到,根据规则我们需要返回原类型:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P] extends R["mapFrom"] ? R["mapTo"] : T[P];
};
至此,我们通过了除了那个联合类型之外的所有的测试用例。在挑战说明中指出可能指定映 射为对象的联合类型。
因此,我们也需要对映射本身进行枚举。我们首先将 R['mapTo']
替换为条件类
型。Typescript 中的条件类型是可分发的(distributive),这意味着他会枚举联合类型
中的每个元素。然而,他作用于条件类型开始的类型。因此,我们以类型参数 R
开始,
并检查匹配的值类型:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P] extends R["mapFrom"]
? R extends { mapFrom: T[P] }
? never
: never
: T[P];
};
可分发(distributive)条件类型会对 R
进行枚举,如果有匹配到值类型 T[P]
,则返
回对应的映射类型:
type MapTypes<T, R extends { mapFrom: unknown; mapTo: unknown }> = {
[P in keyof T]: T[P] extends R["mapFrom"]
? R extends { mapFrom: T[P] }
? R["mapTo"]
: never
: T[P];
};
评论