Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在TypeScript中断言两个接口包含相同的键?_Typescript_Typescript Generics - Fatal编程技术网

如何在TypeScript中断言两个接口包含相同的键?

如何在TypeScript中断言两个接口包含相同的键?,typescript,typescript-generics,Typescript,Typescript Generics,给定接口Foo和Bar,如何静态地断言这两种类型具有相同的键 背景:我有一个界面,既需要用作数据库DTO,也需要用作“模型”类型。对于数据库DTO,原语将是常规JavaScript原语。对于“模型”类型,原语将是标称类型(例如,AccountId而不是string等)。目前,我通过定义两个接口来实现这一点:一个用于DTO,另一个用于模型。但是,我需要一些方法来确保这些接口不会漂移: 接口Dto{ orderId:string; 发票编号:编号; } 界面模型{ orderId:orderId;

给定接口
Foo
Bar
,如何静态地断言这两种类型具有相同的键

背景:我有一个界面,既需要用作数据库DTO,也需要用作“模型”类型。对于数据库DTO,原语将是常规JavaScript原语。对于“模型”类型,原语将是标称类型(例如,
AccountId
而不是
string
等)。目前,我通过定义两个接口来实现这一点:一个用于DTO,另一个用于模型。但是,我需要一些方法来确保这些接口不会漂移:

接口Dto{
orderId:string;
发票编号:编号;
}
界面模型{
orderId:orderId;
发票编号:发票编号;
}
assertKeysEqual()//编译正常
接口Dto{
orderId:string;
发票编号:编号;
x:任何;
}
界面模型{
orderId:orderId;
发票编号:发票编号;
}
assertKeysEqual()//编译错误('Model'不包含'x')
接口Dto{
orderId:string;
发票编号:编号;
}
界面模型{
orderId:orderId;
发票编号:发票编号;
x:任何;
}
assertKeysEqual()//编译错误('Dto'不包含'x')
使用以下方法定义标称类型但是,更一般地说:键类型的形状在不同类型之间可能完全不同。例如,在一种类型中,您可能有
order:OrderId
,在其“扩展”对应类型中,可以将其替换为
order:OrderEntity

导出接口OrderId扩展字符串{
_OrderId:string;
}
导出函数OrderId(值:字符串):OrderId{
返回值(如有);
}

您知道如何实现类似于assertKeysEqual的功能吗?

您可以检查每个接口的键是否是另一个接口的子集:

type AssertEqualKeys<T1 extends object, T2 extends object> =
  [
    keyof T1 extends keyof T2 ? 1 : 0,
    keyof T2 extends keyof T1 ? 1 : 0
  ] extends [1,1] ?  true : false;

const areEqual: AssertEqualKeys<Dto,Model> = true;
类型AssertEqualKeys=
[
T1的键扩展T2的键?1:0,
T2键扩展T1键?1:0
]扩展[1,1]?真:假;
常数等于:AssertEqualKeys=true;
如果键彼此偏移,则该类型将解析为false,并且您将收到错误通知


还有一种仅用于类型的解决方案,它会给出一条可读性较好的错误消息:

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>'.


如何定义OrderId和InvoiceNumber类型?因为如果我很理解你的问题,只需定义类型OrderId=string;类型InvoiceNumber=编号;创建一个可用于Dto和模型对象的接口
OrderId
InvoiceNumber
都是标称类型:我已经更新了描述。天哪,考虑到最初问题中的编辑,类型系统在tswell中取得了真正的进步,不确定这个解决方案是否有效。有些“类型”可能是函数,这还不清楚…@Jerome OP here:键的类型确实可以是函数,但
T1
T2
始终是对象。我认为这个解决方案很好。如果我能接受两个答案,我会的。谢谢你的解决方案,@chrisbajorin
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"; }>'.