Typescript - 根据给定键确定子对象的类型

标签 typescript types

我正在尝试让智能感知与通用类型的接口(interface)一起工作,我希望智能感知和 typescript 检查能够为子级的属性工作,但我不知道如何编写我的界面。

这是我正在尝试做的事情的一个非常简单的示例

interface Foo1 {
    prop1: string;
    prop2: boolean;
}

interface Foo2 {
    prop3: string;
    prop4: boolean;
}

interface Bar1 {
    thing1: Foo1;
    thing2: Foo2;
}
interface Bar2 {
    thing3: Foo1;
    thing4: Foo2;
}

给定这样的结构(在我的项目中,有更多的 Foo's Bar,并且它们都具有更多的属性),我希望能够使用所选的键来生成类似的内容

interface TestItem<T> {
    field: keyof T; //This will be a key of a Bar object
    select: (keyof T[keyof T])[]; //This is trying to state that elements in this array must be a property of Bar[field], e.g if field is "thing1" the only valid elements would be "prop1" or "prop2"
}

interface TestObject<T> {
    itemArray: TestItem<T>[];
}


let test: TestObject<Bar1> = {
            itemArray: [
                {
                    field: "thing1",
                    select: ["prop1"] //error: string is not assignable to type never
                }, {
                    field: "thing2",
                    select: ["prop3"] //error: string is not assignable to type never
                }
            ]
        }

我没想到这会起作用,但我尝试了很多方法,但没有更好的结果。我知道我可以添加更多 GenericType 参数并指定传递给每个 TestItem 的内容,但我希望有人知道一种方法,指定该字段足以让 Typescript 计算出 TestItem 中选择的有效值。

最佳答案

这无法通过单步对象赋值来完成 - 无法根据对象初始化中其他属性的值来限制对象属性的类型。

但语法略有不同,这是可能的:

class  TestObject<T> {

  itemArray: { field: keyof T, select: string[] }[];
  // no constraint could be specified for select here
  // because there is not enough information about T here

  // but we can define a function that will apply constraint
  // when called from a subclass
  testItem<K extends keyof T>(item: { field: K, select: (keyof T[K])[] }) {
    return item
  }
}

class TestBar1 extends TestObject<Bar1> {
  itemArray = [
    this.testItem({ field: "thing1", select: ["prop1"] }), // ok
    this.testItem({ field: "thing2", select: ["prop3"] }), // ok

    this.testItem({ field: "thing1", select: ["prop3"] })  // error:
    // Argument of type '{ field: "thing1"; select: "prop3"[]; }'is not assignable 
    // to parameter of type '{ field: "thing1"; select: ("prop1" | "prop2")[]; }'.
    //  Types of property 'select' are incompatible.
    //    Type '"prop3"[]' is not assignable to type '("prop1" | "prop2")[]'.
    //      Type '"prop3"' is not assignable to type '"prop1" | "prop2"'.
  ]
}

let test = new TestBar1().itemArray;

当错误的项目被删除时,为 test 推断的类型符合预期:

 ({ field: "thing1"; select: ("prop1" | "prop2")[]; } 
| { field: "thing2"; select: ("prop3" | "prop4")[]; })[]

关于Typescript - 根据给定键确定子对象的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48190124/

相关文章:

javascript - 如何在同一声明中使用具有必需属性的多种类型?

c++ - 当您在 C 中定义一个值时,编译器如何选择数据类型

performance - julia:关于函数中泛型类型的几个问题

javascript - 为什么 typescript 没有 "function"类型?

sql-server - Where子句中Int和Varchar(SQL Server)的区别?

javascript - HTMLAnchor 元素下载在 Typescript 中不起作用

angular - 为 typescript 中的 Observable 导入 .of()

angular - 错误 TS5023 : Unknown compiler option 'compilerOptions'

typescript - 使用来自另一个文件的 Typescript 类型定义

swift - 这种类型的名称是什么?