递归类型约束对象属性值

时间:2018-05-24 18:06:32

标签: typescript recursion indexing

我试图以递归方式约束Object上的属性类型。最终目标是给定对象的属性需要是numberstring或其他符合相同描述的嵌套对象(属性类型为number,{{ 1}}或进一步嵌套)

目前,我找到的唯一方法是使用索引签名。就像在这个code example in this TypeScript Playground中演示的那样,但它并不完美,因为需要在课堂上添加额外的行,以及它在我的代码库中的其他地方导致的问题(它会阻止类型推断在某些情况下正常工作)地方)

string

我想知道是否有更好的方法来做到这一点?

1 个答案:

答案 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类型并递归下去,检查每个属性是stringnumber还是{{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();
}

希望有所帮助。祝你好运!