Typescript 对象属性值上的递归类型约束

Typescript 对象属性值上的递归类型约束,typescript,recursion,indexing,Typescript,Recursion,Indexing,我试图以递归的方式约束对象上的属性类型。最终目标是给定对象的属性需要是number,string,或另一个符合相同描述的嵌套对象(属性类型为number,string或进一步嵌套) 目前我找到的唯一方法是使用索引签名。但是,正如本文所演示的,它并不完美,因为需要在类中放入额外的行,以及它在我的代码库中的其他地方导致的问题(它阻止类型推断在某些地方正常工作) type AllowedTypes=string | number | ConstrainedClass; 类型ConstrainedCla

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

目前我找到的唯一方法是使用索引签名。但是,正如本文所演示的,它并不完美,因为需要在类中放入额外的行,以及它在我的代码库中的其他地方导致的问题(它阻止类型推断在某些地方正常工作)

type AllowedTypes=string | number | ConstrainedClass;
类型ConstrainedClass={[key:string]:AllowedTypes};
类Test2{
[key:string]:AllowedTypes;//需要此行
公共物品1:数量;
}
类Test1{
[key:string]:AllowedTypes;//需要此行
公共属性1:字符串;
公共物品2:数量;
公共嵌套属性:Test2;
}
函数somefunction(参数:T){
返回;
}
somefunction(新Test1());

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

您可以使用映射的和自绑定的泛型(我找不到任何好的TypeScript文档;但是有一些可能是好的读物?)。让我们看看:

type Constrained<T> = {
  [K in keyof T]: T[K] extends object ? Constrained<T[K]> : 
    T[K] extends string | number ? T[K] : never
}
注意自绑定泛型,其中
Test
被声明为扩展
constrated
。这将在没有索引签名的情况下强制执行所需的确切约束。如果添加的属性不符合约束条件,则会出现错误,通常类似于
类型“XXX”不能分配给类型“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
}
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();
}
function someFunction<T extends Constrained<T>>(x: T) { }
someFunction(new Test1());
类Test2实现了约束{
公共项目1:编号=1;
}
类Test1实现了约束{
public prop1:string=“a”;
公共物品2:数量=1;
public-nestedProp:Test2=newtest2();
}
(我添加了初始值设定项,因为当您现在不初始化类实例时,TypeScript会出现问题)。您的函数是这样工作的:

interface Test extends Constrained<Test> {
    a: string; // okay
    b: number; // okay
    // c: boolean; // uncommenting this causes an error 
    d: { foo: string;  bar: string } // okay
}
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();
}
function someFunction<T extends Constrained<T>>(x: T) { }
someFunction(new Test1());
函数someFunction(x:T){
someFunction(新Test1());

希望有帮助。祝你好运

不能使用索引类型约束类型,因此仍然可以使用
类Test3{[key:string]:AllowedTypes、someOtherProp:SomeOtherType}
并保持有效。是否要将所有属性类型限制为number或string,或仅具有number或string属性的递归对象?@ExplosionPills确实,我希望实现您描述的递归约束。