在TypeScript中设置必需的属性

时间:2016-01-15 12:16:01

标签: interface typescript redux

在TypeScript中将某些属性标记为必需的正确方法是什么?我们假设我们有某个对象,必须包含 id 字段,但也可以包含任意数量的其他字段:

interface SomeType {
    id: number;
}

let obj: SomeType = { name: "OBJ" };           // GOOD ERROR! We must have `id`
let obj: SomeType = { id: 123 };               // OK
let obj: SomeType = { id: 123, name: "OBJ" };  // BAD ERROR! I just want to add a name

我知道您可以使用问号制作可选属性,如下所示:

interface SomeType {
    id: number;
    name?: string;
    engine?: string;
    mother?: string;
}

但我不希望每次都通过添加和混合不相关的东西来修改此界面。

另一个选择当然是创建一个接口群,每个扩展主要接口,但这听起来像很多代码行:

interface SomeType {
    id: number;
}

interface FirstType extends SomeType {
    name: string;
}

起初我尝试这样做:

interface SomeType extends any {
    id: number;
}

但TypeScript无法找到名称any。也许有这样的感叹号?

interface SomeType {
    id!: number;
}

更新

我在创建Redux操作时使用此类型的界面,这些操作必须具有属性type和任意数量的其他附加属性。实际上有很多动作,所以我不愿意使用any作为一种类型。

3 个答案:

答案 0 :(得分:6)

您可以使用indexer

interface SomeType {
    id: number;
    [key: string]: any;
}

let obj1: SomeType = { name: "OBJ" };           // GOOD ERROR! We must have `id`
let obj2: SomeType = { id: 123 };               // OK
let obj3: SomeType = { id: 123, name: "OBJ" };  // OK

[Playground]

但请注意,即使以下代码(即使用非字符串属性键)对上面的索引器也有效:

let obj4: SomeType = { id: 123, 1: "OBJ" }; // also OK

让人感到困惑,但事实确实如此。

答案 1 :(得分:1)

尝试如下。

table

答案 2 :(得分:1)

  

但我不希望每次都通过添加和混合不相关的东西来修改这个界面。

不要在同一界面中添加或混合不相关的内容。创建单独的接口,然后在必要时使用交集类型组合它们。

interface FirstType {
    id: number;
}

interface SecondType {
    name: string;
}

let myIntersectionObj: FirstType & SecondType = {
    id: 2,
    name: "some string"
};

这在以下情况下很有用:

function myFirstFunction(obj: FirstType) { /* does something */ }
function mySecondFunction(obj: SecondType) { /* does something */ }

function myFunction(obj: FirstType & SecondType) {
    myFirstFunction(obj);
    mySecondFunction(obj);
}

myFunction(myIntersectionObj);

使用交集类型有助于确保在应用程序中输入所有内容,这有助于防止错误。理想情况下,索引类型应仅用于键值对象。