[英]Typescript generic interfaces match on property value
I am still learning TypeScript and all the features it has. 我仍在学习TypeScript及其所有功能。 One of which is constraining generics.
其中之一是约束泛型。 I apologize if this is a commonly asked question, if you have any resources(beyond the docs) that can help me get better at this, please link as comment.
抱歉,这是一个常见问题,如果您有任何资源(超出文档范围)可以帮助我对此有所改善,请链接以评论。
What I'm trying to do is, have the type
properties match between my DeliveryObject
and all the objects inside of deliveryItems
. 我想做的是,让我的
DeliveryObject
和deliveryItems
内部的所有对象之间的type
属性匹配。
Here's an example of code that compiles, but just isn't the end solution that I'm looking for. 这是一个可编译的代码示例,但这不是我想要的最终解决方案。
type DeliveryMethod = 'notification' | 'text' | 'email'
type DeliveryActions = INotificationAction | ITextMessageAction | IEmailAction
interface IDelivery {
type: DeliveryMethod
}
interface INotificationAction extends IDelivery {
type: 'notification'
deviceId: string
message: string
}
interface ITextMessageAction extends IDelivery {
type: 'text'
message: string
}
interface IEmailAction extends IDelivery {
type: 'email'
to: string
subject: string
body: string
}
// I know I need to do something additional here...
interface IDeliveryObject<T extends DeliveryMethod, U extends DeliveryActions> {
type: T
deliveryItems: Array<U>
}
function sendDelivery<K extends DeliveryMethod, Z extends DeliveryActions>(state: IDeliveryObject<K, Z>) {
console.log(state)
}
sendDelivery({
type: 'notification', // <--- needs to match or error out
deliveryItems: [
{
type: 'email', // <--- needs to match or error out
to: 'fake@email.com',
subject: '1235-67890',
body: 'Here is a notification'
}
]
})
I would approach this by using a "type lookup map" to tie together the delivery method and it's associated action object. 我将通过使用“类型查找图”将传递方法及其关联的操作对象绑定在一起来解决此问题。 So I would add another type like this:
所以我要添加另一种这样的类型:
type DeliveryActionTypes = {
"notification": INotificationAction;
"text": ITextMessageAction;
"email": IEmailAction;
}
That type just maps the correct method name to it's action object type. 该类型只是将正确的方法名称映射到其操作对象类型。 Then you can replace the declarations for
DeliveryMethod
and DeliveryActions
with: 然后,您可以将
DeliveryMethod
和DeliveryActions
的声明替换为:
type DeliveryMethod = keyof DeliveryActionTypes;
type DeliveryActions = DeliveryActionTypes[keyof DeliveryActionTypes];
That will allow you to easily lookup the correct action if you know the name of the method. 如果您知道该方法的名称,则可以轻松查找正确的操作。 You can use that in your
IDeliveryObject
to make sure that the two types correspond: 您可以在
IDeliveryObject
使用它来确保两种类型相对应:
interface IDeliveryObject<T extends DeliveryMethod> {
type: T;
// This is the type lookup, note the `DeliveryActionTypes[T]` part.
deliveryItems: Array<DeliveryActionTypes[T]>;
}
Now you can simplify the signature for the sendDelivery
function, since all it needs now is the method name: 现在,您可以简化
sendDelivery
函数的签名,因为它现在所需要的只是方法名称:
function sendDelivery<K extends DeliveryMethod>(state: IDeliveryObject<K>) {
console.log(state)
}
With all that, you'll get an error if the types don't match: 所有这些,如果类型不匹配,则会出现错误:
sendDelivery({
type: 'notification',
deliveryItems: [
{
type: 'email',
to: 'fake@email.com', // <-- error on this line, see below
subject: '1235-67890',
body: 'Here is a notification'
}
]
})
Type '{ type: "email"; to: string; subject: string; body: string; }' is not assignable to type 'INotificationAction'.
As you can see, Typescript correctly concludes that the items in the array should be of type INotificationAction
, and produces an error when they are not. 正如你所看到的,打字稿正确的结论是,数组中的项目应该是类型
INotificationAction
,而当它们不产生错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.