说我有一些界面:
export interface MyDocument {
id: string,
collection: string[];
}
然后我创建一个新的(将现有类型强制转换为该类型):
const workingDocument = <MyDocument>document;
最后,我有一个if语句块来检查它是否确实包含我在该接口中指定的所有内容:
if (!workingDocument.id) {
throw new Error("Document missing `id`");
} else if (!workingDocument.collection) {
throw new Error("Document missing `collection` array");
}
但是我似乎并不喜欢这样,如果语句可能会永远增长并且很难维护。
有更好的方法吗?
谢谢。
答案 0 :(得分:1)
如果要在内部创建/使用此Document类型,则可以使用类型/接口自行声明其类型,而无需强制转换。
但是,如果文档来自您的打字稿应用程序之外,则需要进行某种形式的手动类型保护/检查(您要避免的事情)。
答案 1 :(得分:1)
如果我的理解正确,那么您正在要求运行时检查对象是否包含接口定义的所有属性。单独使用接口是不可能的,因为与接口关联的类型信息不会使它进入运行时。换句话说,当我们运行TypeScript编译器时,该接口仅 有用。
您可以做的是创建一个包含接口所有属性的架构。然后,您可以遍历该架构以检查所有属性是否存在于您的对象上。这是一个看起来如何的示例。我已将示例包装在user-defined type guard中。
export interface MyDocument {
id: string,
collection: string[];
}
const isMyDocument = (input: any): input is MyDocument => {
const schema: Record<keyof MyDocument, string> = {
id: 'string',
collection: 'array'
};
const missingProperties = Object.keys(schema)
.filter(key => input[key] === undefined)
.map(key => key as keyof MyDocument)
.map(key => new Error(`Document is missing ${key} ${schema[key]}`));
// throw the errors if you choose
return missingProperties.length === 0;
}
const obj = {};
if (isMyDocument(obj)) {
// the compiler now knows that obj has all of its properties
obj.collection;
}
这是上面的代码in the TypeScript playground。
以下是使用...
运算符扩展架构的方法。
interface ParentDocument {
id: string,
collection: [],
}
interface ChildDocument extends ParentDocument {
name: string;
}
const schemaParent: Record<keyof ParentDocument, string> = {
id: 'string',
collection: 'array'
};
const schemaChild: Record<keyof ChildDocument, string> = {
name: 'string',
...schemaParent,
};