我试图以递归方式约束Object上的属性类型。最终目标是给定对象的属性需要是number
,string
或其他符合相同描述的嵌套对象(属性类型为number
,{{ 1}}或进一步嵌套)
目前,我找到的唯一方法是使用索引签名。就像在这个code example in this TypeScript Playground中演示的那样,但它并不完美,因为需要在课堂上添加额外的行,以及它在我的代码库中的其他地方导致的问题(它会阻止类型推断在某些情况下正常工作)地方)
string
我想知道是否有更好的方法来做到这一点?
答案 0 :(得分:1)
你可以使用映射的conditional types和自我限制的泛型(我找不到任何好的TypeScript文档来获得你想要的东西;但有analogous uses in Java可能是好的读取?) 。我们来看看:
type Constrained<T> = {
[K in keyof T]: T[K] extends object ? Constrained<T[K]> :
T[K] extends string | number ? T[K] : never
}
Constrained<T>
采用T
类型并递归下去,检查每个属性是string
,number
还是{{1} }也符合object
。它不喜欢的任何属性都替换为Constrained
。
有了这个,你可以像这样创建你的界面:
never
注意自我限制的泛型,其中interface Test extends Constrained<Test> {
a: string; // okay
b: number; // okay
// c: boolean; // uncommenting this causes an error
d: { foo: string; bar: string } // okay
}
被声明为扩展Test
。这会在没有索引签名的情况下强制执行您想要的确切约束。如果添加不符合约束的属性,则会出现错误,通常类似于Constrained<Test>
。
使用类来执行此操作看起来像这样:
Type 'XXX' is not assignable to type 'never'
(我添加了初始化程序,因为当你不初始化类实例时,TypeScript会立即抱怨)。你的功能是这样的:
class Test2 implements Constrained<Test2> {
public prop1: number = 1;
}
class Test1 implements Constrained<Test1> {
public prop1: string = "a";
public prop2: number = 1;
public nestedProp: Test2 = new Test2();
}
希望有所帮助。祝你好运!