1

所以我有这个帮助函数,它允许我根据结构匹配替换类型:

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)

...显然,它会深入搜索 Array 直到找到要替换的内容,对吗?正确的?错误的:

Type alias 'RecursiveArrayReplace' circularly references itself.

还没等我擦干眼泪,就有人扔给我一句:

type TupleStringNumberThing = { value: [string, number] }

...这让我蜷缩成胎儿的姿势,除非你们帮助我:(

4

1 回答 1

3

鉴于您的特定示例,我会这样写:

type DeepReplace<T, C, A> = T extends C ? A : T extends object ? {
    [P in keyof T]: DeepReplace<T[P], C, A> } : T;

如果您使用的是 TS3.1 或更高版本,这应该适用于您的所有类型,包括数组/元组:

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]; }

显然你可以找到其他边缘情况......接受/返回C的函数应该与接受/返回的函数一起使用A吗?这些可能会被处理,但如果您的用例不需要它,则可能不值得额外的复杂性。

好的,希望有帮助;祝你好运!

Playground 代码链接

于 2020-04-23T18:58:21.437 回答