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.
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.
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.
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,
};
constructor(data: any) { Object.assign(this,data); }- voila - whatever you pass into this class automatically adheres to whatever properties are on the class, according to the compiler....runtime is a different story. Typescript is supposed to catch potential problems at compile time, use it for it's strengths. If you are casting and you don't know for sure what you are casting, and end up writing ifs to check, then you're doing typescript wrong.