Typescript通用接口匹配属性值

时间:2018-06-08 19:25:08

标签: typescript generics interface

我还在学习TypeScript及其拥有的所有功能。其中之一是限制泛型。如果这是一个常见问题我很抱歉,如果你有任何资源(除了文档之外)可以帮助我在这方面做得更好,请链接为评论。

我想要做的是,type属性与DeliveryObjectdeliveryItems内的所有对象匹配。

以下是编译代码的示例,但并不是我正在寻找的最终解决方案。

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'
    }
  ]
})

1 个答案:

答案 0 :(得分:2)

我会通过使用“类型查找映射”将传递方法与其关联的操作对象联系在一起来实现此目的。所以我会添加另一种类型:

type DeliveryActionTypes = {
    "notification": INotificationAction;
    "text": ITextMessageAction;
    "email": IEmailAction;
}

该类型只是将正确的方法名称映射到它的操作对象类型。然后,您可以将DeliveryMethodDeliveryActions的声明替换为:

type DeliveryMethod = keyof DeliveryActionTypes;
type DeliveryActions = DeliveryActionTypes[keyof DeliveryActionTypes];

如果您知道方法的名称,那么您可以轻松查找正确的操作。您可以在IDeliveryObject中使用它来确保两种类型对应:

interface IDeliveryObject<T extends DeliveryMethod> {
    type: T;

    // This is the type lookup, note the `DeliveryActionTypes[T]` part.
    deliveryItems: Array<DeliveryActionTypes[T]>;
}

现在您可以简化sendDelivery函数的签名,因为它现在需要的只是方法名称:

function sendDelivery<K extends DeliveryMethod>(state: IDeliveryObject<K>) {
  console.log(state)
}

尽管如此,如果类型不匹配,您将收到错误:

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

正如您所看到的,Typescript正确地断定数组中的项应该是INotificationAction类型,并且当它们不是时会产生错误。