TypeScript 中泛型的深度条件类型
Deep Conditional Type of a Generic in TypeScript
所以我有这个辅助函数,允许我根据结构匹配替换类型:
type Replace<T, C, A> = {
[P in keyof T]: T[P] extends C ? A : T[P]
}
这允许我执行以下操作:
type NumberThing = { value: number }
type StringThing = Replace<NumberThing, number, string>
const a: StringThing = { value: "cenas" }
一切都很好,但有人这样做:
type ArrayOfNumberThing = { value: Array<number> }
好的,所以,我只是添加一个新条件...
type Replace<T, C, A> = {
[P in keyof T]: T[P] extends C ? A : (T[P] extends Array<C> ? Array<A> : T[P])
}
然后输入:
type ArrayOfNumberThing = { value: Array<number>, simpleValue: number }
type ArrayOfStringThing = Replace<ArrayOfNumberThing, number, string>
const b: ArrayOfStringThing = { value: ["cenas"], simpleValue: "still works" }
但是这家伙很固执,现在扔给我一个:
type CrazyNumberThing = { value: Array<Array<Array<number>>> }
好吧,我总能做到这一点:
type RecursiveArrayReplace<T, C, A> = T extends C ? A : (T extends Array<infer E> ? RecursiveArrayReplace<E, C, A> : T)
... 显然,这会深入搜索数组,直到找到要替换的内容,对吗?正确的?错误:
Type alias 'RecursiveArrayReplace' circularly references itself.
在我擦干眼泪之前,有人给我扔了一个:
type TupleStringNumberThing = { value: [string, number] }
...这让我蜷缩在胎儿的位置,除非你们帮助我:(
鉴于你的具体例子,我会这样写:
type DeepReplace<T, C, A> = T extends C ? A : T extends object ? {
[P in keyof T]: DeepReplace<T[P], C, A> } : T;
这应该适用于所有类型 including arrays/tuples if you're using TS3.1 or above:
type NumberThing = { value: number }
type StringThing = DeepReplace<NumberThing, number, string>
// type StringThing = { value: string; }
type ArrayOfNumberThing = { value: Array<number>, simpleValue: number }
type ArrayOfStringThing = DeepReplace<ArrayOfNumberThing, number, string>;
// type ArrayOfStringThing = { value: string[]; simpleValue: string; }
type CrazyNumberThing = { value: Array<Array<Array<number>>> };
type CrazyStringThing = DeepReplace<CrazyNumberThing, number, string>;
// type CrazyStringThing = { value: string[][][]; }
type TupleStringNumberThing = { value: [string, number] };
type TupleStringStringThing = DeepReplace<TupleStringNumberThing, number, string>;
// type TupleStringStringThing = { value: [string, string]; }
显然您可以找到其他边缘情况... accept/return C
的函数应该与 accept/return A
的函数一起使用吗?这些可能可以处理,但如果您的用例不需要它,那么额外的复杂性可能不值得。
好的,希望对您有所帮助;祝你好运!
所以我有这个辅助函数,允许我根据结构匹配替换类型:
type Replace<T, C, A> = {
[P in keyof T]: T[P] extends C ? A : T[P]
}
这允许我执行以下操作:
type NumberThing = { value: number }
type StringThing = Replace<NumberThing, number, string>
const a: StringThing = { value: "cenas" }
一切都很好,但有人这样做:
type ArrayOfNumberThing = { value: Array<number> }
好的,所以,我只是添加一个新条件...
type Replace<T, C, A> = {
[P in keyof T]: T[P] extends C ? A : (T[P] extends Array<C> ? Array<A> : T[P])
}
然后输入:
type ArrayOfNumberThing = { value: Array<number>, simpleValue: number }
type ArrayOfStringThing = Replace<ArrayOfNumberThing, number, string>
const b: ArrayOfStringThing = { value: ["cenas"], simpleValue: "still works" }
但是这家伙很固执,现在扔给我一个:
type CrazyNumberThing = { value: Array<Array<Array<number>>> }
好吧,我总能做到这一点:
type RecursiveArrayReplace<T, C, A> = T extends C ? A : (T extends Array<infer E> ? RecursiveArrayReplace<E, C, A> : T)
... 显然,这会深入搜索数组,直到找到要替换的内容,对吗?正确的?错误:
Type alias 'RecursiveArrayReplace' circularly references itself.
在我擦干眼泪之前,有人给我扔了一个:
type TupleStringNumberThing = { value: [string, number] }
...这让我蜷缩在胎儿的位置,除非你们帮助我:(
鉴于你的具体例子,我会这样写:
type DeepReplace<T, C, A> = T extends C ? A : T extends object ? {
[P in keyof T]: DeepReplace<T[P], C, A> } : T;
这应该适用于所有类型 including arrays/tuples if you're using TS3.1 or above:
type NumberThing = { value: number }
type StringThing = DeepReplace<NumberThing, number, string>
// type StringThing = { value: string; }
type ArrayOfNumberThing = { value: Array<number>, simpleValue: number }
type ArrayOfStringThing = DeepReplace<ArrayOfNumberThing, number, string>;
// type ArrayOfStringThing = { value: string[]; simpleValue: string; }
type CrazyNumberThing = { value: Array<Array<Array<number>>> };
type CrazyStringThing = DeepReplace<CrazyNumberThing, number, string>;
// type CrazyStringThing = { value: string[][][]; }
type TupleStringNumberThing = { value: [string, number] };
type TupleStringStringThing = DeepReplace<TupleStringNumberThing, number, string>;
// type TupleStringStringThing = { value: [string, string]; }
显然您可以找到其他边缘情况... accept/return C
的函数应该与 accept/return A
的函数一起使用吗?这些可能可以处理,但如果您的用例不需要它,那么额外的复杂性可能不值得。
好的,希望对您有所帮助;祝你好运!