Law*_*eld 4 typescript typescript-generics
给定接口Foo和Bar,我如何静态断言两种类型具有相同的键?
背景:我有一个接口,需要用作数据库 DTO 和“模型”类型。对于数据库 DTO,原语将是常规 JavaScript 原语。对于“模型”类型,原语将是名义类型(例如,AccountId而不是string等)。目前,我通过定义 2 个接口来实现这一目标:一个用于 DTO,一个用于模型。但是,我想要一些方法来确保这些接口不会漂移:
interface Dto {
orderId: string;
invoiceNo: number;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
}
assertKeysEqual<Dto, Model>() // Compiles OK
Run Code Online (Sandbox Code Playgroud)
interface Dto {
orderId: string;
invoiceNo: number;
x: any;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
}
assertKeysEqual<Dto, Model>() // Compile ERROR ('Model' does not contain 'x')
Run Code Online (Sandbox Code Playgroud)
interface Dto {
orderId: string;
invoiceNo: number;
}
interface Model {
orderId: OrderId;
invoiceNo: InvoiceNumber;
x: any;
}
assertKeysEqual<Dto, Model>() // Compile ERROR ('Dto' does not contain 'x')
Run Code Online (Sandbox Code Playgroud)
名义类型使用以下方法定义。然而,更一般地说:不同类型的按键类型的形状可能完全不同。例如,在一种类型中,您可能有order: OrderId,可以将其替换order: OrderEntity为其“扩展”对应类型。
export interface OrderId extends String {
_OrderId: string;
}
export function OrderId(value: string): OrderId {
return value as any;
}
Run Code Online (Sandbox Code Playgroud)
知道如何实施类似的事情assertKeysEqual吗?
还有一个仅类型的解决方案,它提供了一些可读的错误消息:
type AssertKeysEqual<
T1 extends Record<keyof T2, any>,
T2 extends Record<keyof T1, any>
> = never
type Assertion = AssertKeysEqual<{a:1}, {a:1, b: 'x'}>
// ERROR: Property 'b' is missing in type '{ a: 1; }' but required in type 'Record<"a" | "b", any>'.
Run Code Online (Sandbox Code Playgroud)
更新:在 TypeScript 4.2+ 中,如果您为记录引入额外的类型,则类型别名保留( docs)允许稍微令人愉快的错误消息:ShapeOf
type ShapeOf<T> = Record<keyof T, any>
type AssertKeysEqual<X extends ShapeOf<Y>, Y extends ShapeOf<X>> = never
type Assertion = AssertKeysEqual<{a:1}, {a:1, b: 'x'}>
// ERROR: Property 'b' is missing in type '{ a: 1; }' but required in
// type 'ShapeOf<{ a: 1; b: "x"; }>'.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1035 次 |
| 最近记录: |