简体   繁体   English

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

[英]Typescript - Check an object has all interface properties

Say I have some interface: 说我有一些界面:

export interface MyDocument {
    id: string,
    collection: string[];
}

I then create a new (well cast an existing to that type): 然后,我创建一个新的(将现有类型强制转换为该类型):

const workingDocument = <MyDocument>document;

And finally, I have this if statement block to check whether it actually contains everything I have specified in that interface: 最后,我有这个if语句块来检查它是否确实包含我在该接口中指定的所有内容:

if (!workingDocument.id) {
   throw new Error("Document missing `id`");
} else if (!workingDocument.collection) {
   throw new Error("Document missing `collection` array");
}

However I don't seem to like this as that if statement could grow forever and not very good to maintain. 但是我似乎不喜欢这样,如果语句可以永远增长并且很难维护。

Is there a better way? 有没有更好的办法?

Thanks. 谢谢。

If you're creating / using this Document type internally, you can use types/interfaces to assert their types - for yourself - without the need to cast. 如果在内部创建/使用此Document类型,则可以使用类型/接口自己声明其类型,而无需强制转换。

However, if the documents are from outside of your typescript app, you'll need to result to some form of manual type guarding / checking (the thing you want to avoid). 但是,如果文档来自您的打字稿应用程序外部,则需要进行某种形式的手动类型保护/检查(要避免的事情)。

Original Answer 原始答案

If I understand correctly, you're asking for a runtime check that an object includes all the properties that an interface defines. 如果我理解正确,那么您正在要求运行时检查对象是否包含接口定义的所有属性。 That is not possible with an interface on its own, because the type information associated with an interface does not make it to runtime; 单独使用接口是不可能的,因为与接口关联的类型信息不会使它进入运行时。 in other words, the interface is only useful when we run the TypeScript compiler. 换句话说,该接口在我们运行TypeScript编译器时才有用。

What you could do is to create an schema that contains all the properties of the interface. 您可以做的是创建一个包含接口所有属性的架构。 Then you could loop over that schema to check that all the properties exist on your object. 然后,您可以遍历该架构以检查所有属性是否存在于您的对象上。 Here is an example of how that might look. 这是一个看起来如何的示例。 I have wrapped the example in a user-defined type guard . 我已将示例包装在用户定义的类型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;
} 

Here is the above code in the TypeScript playground . 这是TypeScript操场上的上述代码。

Answer to Question in the Comments 在评论中回答问题

Here is how you might use the ... operator to extend a schema. 这是使用...运算符扩展架构的方法。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM