从多种类型中创建对象类型

时间:2019-10-14 13:49:55

标签: typescript types

我试图弄清楚如何创建基于对象的类型,该类型的键是固定的,并映射到类型的特定属性。值应使用与属性对应的类型。

请考虑以下类型:

interface CooldownError {
  message: 'cooldown'
  minutes: Number
}

interface AbortError {
  message: 'error'
  description: string
}

基于message属性,我想要一种具有以下签名的类型:

type ErrorCollection = {
    cooldown: (e: CooldownError) => void;
    error: (e: AbortError) => void;
}

到目前为止我尝试过的事情:

type GQLErrors = CooldownError | AbortError;
type ErrorCollection = { [key in GQLErrors['message']]: (e: GQLErrors) => void };

虽然这适用于键,但所有值均设置为联合。我没有找到以某种方式解构工会的方法。这有可能吗?

2 个答案:

答案 0 :(得分:1)

假设您已经承诺要使用类似GQLErrors的联合类型(并且您需要这样做,因为否则无法知道要进行的迭代),您可以调整{ {1}}像这样:

ErrorCollection

在这里,我们使用内置实用程序类型Extract<T, U>,该类型采用联合类型type ErrorCollection = { [K in GQLErrors['message']]: (e: Extract<GQLErrors, { message: K }>) => void }; ,并且仅返回与T匹配的T成员的联合。因此,当UExtract<GQLErrors, { message: K }>CooldownError会变成K,而当"cooldown"AbortErrorK会变成"error"。您可以验证编译器将ErrorCollection视为:

/*
type ErrorCollection = {
    cooldown: (e: CooldownError) => void;
    error: (e: AbortError) => void;
}
*/

这就是您想要的。希望能有所帮助;祝你好运!

Link to code

答案 1 :(得分:0)

您可以使用中间界面,如下所示:

interface CooldownError {
  message: 'cooldown'
  minutes: Number
}

interface AbortError {
  message: 'abort' // changed from 'error'
  description: string
}

interface Intermediate {
  cooldown:  CooldownError
  abort: AbortError
}

type ErrorCollection = {[K in keyof Intermediate]: (e: Intermediate[K]) => void}

请注意,您有责任使Intermidate接口键与错误的message键相同。