Given the interfaces Foo and Bar, how can I statically assert both types have the same keys?
Background: I have an interface that needs to be used as both a database DTO and also as a 'model' type. For the database DTO, primitives will be regular JavaScript primitives. For the 'model' type, primitives will be nominal types (e.g. AccountId instead of string, etc.). Currently, I am achieving this by defining 2 interfaces: one for the DTO, and one for the model. However, I want some way to ensure these interfaces don't drift:
interface Dto {
orderId: string;
invoiceNo: number;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
}
assertKeysEqual<Dto, Model>() // Compiles OK
interface Dto {
orderId: string;
invoiceNo: number;
x: any;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
}
assertKeysEqual<Dto, Model>() // Compile ERROR ('Model' does not contain 'x')
interface Dto {
orderId: string;
invoiceNo: number;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
x: any;
}
assertKeysEqual<Dto, Model>() // Compile ERROR ('Dto' does not contain 'x')
Nominal types are defined using the following method. However, more generally: the shape of the key types could be completely different between the types. For example, in one type you may have order: OrderId, which could be replaced with order: OrderEntity in its "expanded" counterpart type.
export interface OrderId extends String {
_OrderId: string;
}
export function OrderId(value: string): OrderId {
return value as any;
}
Any idea how to implement something like assertKeysEqual?