打字稿-检查对象是否具有所有接口属性

时间:2019-05-14 00:47:54

标签: javascript typescript interface

说我有一些界面:

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");
}

但是我似乎并不喜欢这样,如果语句可能会永远增长并且很难维护。

有更好的方法吗?

谢谢。

2 个答案:

答案 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,
};