给定一个类型,例如:
type PromiseFunc = () => Promise<unknown>;
type A = {
key1: string;
key2: string;
key3: PromiseFunc;
key4: string;
key5: PromiseFunc;
key6: SomeOtherType1[];
key7: SomeOtherType2[];
key8: string;
key9: PromiseFunc;
// ...
};
给定如上所述的类型,我想创建一个新的类型B
,这样:
A
中类型为string
的所有密钥在B
中都作为类型string
存在A
中类型为PromiseFunc
的所有密钥在B
中作为类型string
存在A
中属于数组类型的所有键都被排除在B
之外
这在某种通用方式下可能吗?我有数百种类型,如A
,但我想找到一种方法将它们转换为B
之类的类型。我不控制A
类型的生成。
编辑:链接到其他解决方案:https://www.typescriptlang.org/play?#code/C4TwDgpgBAIghsCAFATgewLYEsDO0C8UAFAJRT4B8UqmuEAPPIhQNwBQokUA4hAHYQUWAMY1sectXTiGOYEL4BzCmzYB6NVAAq4aMDRQAZlgA2iFB12wEcSQG82UKAGsIIAIwAuKHIWL2Tq4gAEzeTMjSdI4ubgDM3nB8IADaALrRQQAs3rwCQqKReBluAKzepORUYnT0fACuGABGgioAvuyWXACycGCouBhwOpBaaADKJmh8WM70APKNAFZQEAAeiHwAJjhQAEoQwmgom-S+WEoANFCJIBRXPcDCABYAanAmdRDDEFf7OHVmN4fL66KiEBxOziaaSg5xiIDQhmoIm0ScCWFzRUAhTjx0LcsL48MRUAxqW8GIJIFSK3W-G2UAezyBn2+UAA-FAoYTvAIAG6CAJ41rJIKk8nCgUvYQf6A95s3TsdqTjQfqDap4UYTKYzb4AYSmgpQ5noWjBTN6-Rwg2+usm01mWiu4W1Pyg9aLSgADJrX0hHahrpHf qXVdcoIRB6oAAfHzyc6KK5nJQqNiHPhyHyYCCsiDeTVwD3h51Gk2Cc1MOBW3FBLxQADkhjQaGbWMCblCUHcXfh2RbWE2mU7bHaQA
好吧,我想好了如何做到这一点,我相信有一种更优化的方法来组合这些类型转换,但这就是我目前所拥有的,它很有效:
type PromiseFunc = () => Promise<unknown>;
// A type whose keys we want to drop.
type SomeOtherType1 = {
key1: string[];
};
// Another type whose keys we want to drop.
type SomeOtherType2 = {
key1: number;
};
type A = {
key1: string;
key2: string;
key3: PromiseFunc;
key4: string;
key5: PromiseFunc;
key6: SomeOtherType1[];
key7: SomeOtherType2[];
key8: string;
key9: PromiseFunc;
};
// Start by building a filter type we can call with the types we want
// and converting all other types to a standard type.
type Filter<T, ConditionOne, ConditionTwo> = {
[Key in keyof T]: T[Key] extends ConditionOne
? string
: T[Key] extends ConditionTwo
? string
: number;
};
// Do the conversion to a new type that only has string and number types.
type ConvertedType = Filter<A, string, PromiseFunc>;
// Now that we only have two types we can drop all the types that don't
// match the type we want (which is string), we'll convert all those keys
// to never which will drop them from our new type.
type PickByValueType<T, U> = {
[K in keyof T as K extends K ? (T[K] extends U ? K : never) : never]: T[K];
};
// Generate the final type that is only the keys which are strings.
type FilteredType = PickByValueType<ConvertedType, string>;
我遇到的主要问题是在我有number
的地方,我最初有never
,我认为它应该自动将这些键从类型中排除,但它没有(只是将类型更改为never(。在TS问题跟踪器上查看此问题提供了一些见解。显然,这是我正在使用的TS 4.1.2中的内容,但我肯定还是做错了什么,我相信如果Filter
类型与PickByValueType
类型相结合,这可以进一步优化。
对于以后可能遇到这个答案的人来说,这里必须使用两种类型转换的原因是因为我们需要考虑和转换多种类型。如果你想简单地包括几种类型,你可以这样做:
...
type GrabTypes<T, U, U2> = {
[K in keyof T as K extends K
? T[K] extends U
? K
: T[K] extends U2
? K
: never
: never]: T[K];
};
type GrabbedTypes = GrabTypes<A, string, SomeOtherType1[]>
关于使用omit
排除某些类型,SO上已经有几个问题,但我找不到很多好的例子可以让你删除不同类型的多个键。我认为这也可以以某种方式扩展到处理转换,但我想不出如何在三元运算符的约束下进行转换
...
type GrabTypesAndConvertOne<T, U, TypeToConvert> = {
[K in keyof T as K extends K
? T[K] extends U
? K
: T[K] extends TypeToConvert
? K // <- Here is where the type change logic would live
: never
: never]: T[K];
};
type GrabbedTypes = GrabTypesAndConvertOne<A, string, PromiseFunc>