在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
作为一种类型。
答案 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
但请注意,即使以下代码(即使用非字符串属性键)对上面的索引器也有效:
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);
使用交集类型有助于确保在应用程序中输入所有内容,这有助于防止错误。理想情况下,索引类型应仅用于键值对象。