Reputation: 979
I have the following TypeScript interface that is used as a database entity for an ORM library:
export interface Entity {
id?: number;
someColumn: string;
someOtherValue: number;
otherColumn: string;
}
Notice the optional id
property, which is either the primary key of the entity or undefined.
If it is undefined, then this means that the entity does not exist in the underlying database.
However, many functions only accept Entity
-objects that have a valid id.
Therefore, I would like to introduce a new interface that looks like this (without the "?"):
export interface ValidEntity {
id: number;
someColumn: string;
someOtherValue: number;
otherColumn: string;
}
Now my problem is that I do not want to duplicate all the properties from the original Entity
-interface.
How can I "extend" the Entity
-interface with a constraint to enforce that id
must not be undefined?
Another question is the same thing in the opposite direction.
Suppose that we already have the ValidEntity
interface and want to create an Entity
interface that relaxes the id
property to allow undefined. How can we accomplish this relaxation without duplicating properties?
Upvotes: 2
Views: 1913
Reputation: 2679
Although there might be other ways that produce prettier error messages, a quick intersection type will do the trick.
export interface Entity {
id?: number;
someColumn: string;
someOtherValue: number;
otherColumn: string;
}
type ValidEntity = Entity & { id: number };
// Alternate solution:
// type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
// type ValidEntity = RequiredBy<Entity, "id">
function f(e: ValidEntity) { }
let obj = {
someColumn: "1",
someOtherValue: 2,
otherColumn: "3"
}
f(obj);
// Property 'id' is missing in type '{ someColumn: string; someOtherValue:
// number; otherColumn: string; }' but required in type '{ id: number; } '.
Going the opposite direction is a little bit more tricky. Based on this answer, you can use utility types as follows:
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
interface ValidEntity {
id: number;
someColumn: string;
someOtherValue: number;
otherColumn: string;
}
type Entity = PartialBy<ValidEntity, 'id'>
Upvotes: 2