首先,我想要以下结果:
type Wrapper<ID extends string> = { id: ID };
type WrapperWithPayload<ID extends string, Payload> = { id: ID, payload: Payload };
enum IDs {
FOO = "ID Foo",
BAR = "ID Bar",
BAZ = "ID Baz"
}
interface AssociatedTypes {
[IDs.FOO]: number;
[IDs.BAR]: number[];
}
type Result = MagicMapper<IDs, AssociatedTypes>
/*
* Result should have this type:
* {
* [IDs.FOO]: WrapperWithPayload<IDs.FOO, number>;
* [IDs.BAR]: WrapperWithPayload<IDs.BAR, number[]>;
* [IDs.BAZ]: Wrapper<IDs.BAZ>;
* }
*/
换句话说,我想提供一些字符串和一个映射,这些映射将那些字符串的子集映射到另一种类型。然后,我想使用字符串作为键来创建一个新类型。对于每个字符串/键,如果存在映射,则我要使用类型A,否则要使用类型B。
现在,我的方法如下:
type MagicMapper<T extends string, Mapping extends { [key in T]?: any }> = {
[key in T]: Mapping[key] extends never ? Wrapper<key> : WrapperWithPayload<key, Mapping[key]>;
};
那几乎可以达成目标:
type Result = {
"ID Foo": WrapperWithPayload<IDs.FOO, number>;
"ID Bar": WrapperWithPayload<IDs.BAR, number[]>;
"ID Baz": Wrapper<IDs.BAZ> | WrapperWithPayload<IDs.BAZ, any>;
}
Baz键上的联合是错误的。我认为该错误位于extends never
条件内,但是用例如undefined代替它只会使情况更糟:
type MagicMapper<T extends string, Mapping extends { [key in T]?: any }> = {
[key in T]: Mapping[key] extends undefined ? Wrapper<key> : WrapperWithPayload<key, Mapping[key]>;
};
type Result = {
"ID Foo": Wrapper<IDs.FOO>;
"ID Bar": Wrapper<IDs.BAR>;
"ID Baz": Wrapper<IDs.BAZ>;
}
有什么方法可以使事情按我需要的方式工作?
答案 0 :(得分:1)
您可以将Mapping
中密钥存在的测试更改为Mapping extends { [P in key]: infer U }
,一切都会按预期进行:
type Wrapper<ID extends string> = { id: ID };
type WrapperWithPayload<ID extends string, Payload> = { id: ID, payload: Payload };
enum IDs {
FOO = "ID Foo",
BAR = "ID Bar",
BAZ = "ID Baz"
}
interface AssociatedTypes {
[IDs.FOO]: number;
[IDs.BAR]: number[];
}
type MagicMapper<T extends string, Mapping extends { [key in T]?: any }> = {
[key in T]: Mapping extends { [P in key]: infer U } ? WrapperWithPayload<key, U>: Wrapper<key> ;
};
type Result = MagicMapper<IDs, AssociatedTypes>
// same as :
type Result = {
"ID Foo": WrapperWithPayload<IDs.FOO, number>;
"ID Bar": WrapperWithPayload<IDs.BAR, number[]>;
"ID Baz": Wrapper<IDs.BAZ>;
}