嗨,他有2个接口和一个类型
interface A {
k1: string
k2: string
}
interface B {
k3: string
k4: A
}
type Error = { key:string, value:string}
我已经开发了一个声明,该声明使用给定接口的所有键和类型= Error []
创建一个接口 type AutoErrors<P> = {
[K in keyof P]-?: Error[]
}
这很好,因为AutoErrors<A>
给出了{
k1: Error[]
k2: Error[]
}
但是现在我希望它是递归的,即,如果参数类型键不是字符串类型,我希望它的类型为AutoErrors<T>
例如AutoErrors<B>
应该是{
k3: Error[],
k4: AutoErrors<A>
}
我尝试过
type AutoErrors<X> = { [K in keyof X]-?: X[K] extends string ? Error[] : AutoErrors<X[K]> }
但却无法正常工作,好像测试X [K]扩展字符串的解释不正确
答案 0 :(得分:1)
您可以使用类似于DeepReadOnly的方法
export type primitive = string | number | boolean | undefined | null
export type DeepError<T> =
T extends (infer U)[] ? Array<DeepErrorObject<U>> :
T extends primitive ? Error[] : DeepErrorObject<T>;
export type DeepErrorObject<T> = {
readonly [P in keyof T]: DeepError<T[P]>
}
// sample usage
interface A {
k1: string
k2: string
}
interface B {
k3: string
k4: A
k4Arr: B[]
}
type Error = {
key:string,
message:string
}
type ErrorA = DeepError<B>
let d: ErrorA;
d.k4Arr[0].k3; // Error[]
答案 1 :(得分:1)
您的问题works in the Playground中发布的代码,因此我怀疑还有其他情况。事实证明,问题与可选属性有关,例如
type UhOh = AutoErrors<{ a?: string }>; // becomes {a: string}, not good
在这种情况下,原始的AutoErrors<>
定义不起作用,因为string | undefined
不扩展string
。如您所知,解决此问题的方法是检查string | undefined
而不只是string
:
type AutoErrors<X> = {
[K in keyof X]-?: X[K] extends string | undefined ?
Error[] : AutoErrors<X[K]>
}
有效:
type Okay = AutoErrors<{ a?: string }>; // becomes {a: Error[]}, as expected
很高兴您发现发生了什么事。