TypeScript:区分元组中的联合和值

标签 typescript discriminated-union

是否可以根据元组属性中的第一个元素来区分联合类型?

例如

type Landing = {
  tokens: ['landing']
};

type Month = {
  tokens: ['month', string]
};

type Day = {
  tokens: ['day', string, string]
};

type Route =
  | Month
  | Day
  | Landing;

let route: Route = getRoute();

if(route.tokens[0] === 'day') {
  // resolve to Day type
}

更新: 如果没有直接的方法来做到这一点,我会很高兴使用自定义类型防护,但还无法让其工作。为了澄清,我想要一个可以区分联合的类型保护器,而不是对每个变体进行显式检查。

例如

if(typeGuard(route, 'day')) {
    // compiler knows this id Day type
}
else if(typeGuard(route, 'month')) {
    // compiler knows this is Month type
}

最佳答案

编辑 自最初的答案以来, typescript 在区分联合方面已经变得更好,因此这在 typescript 3.3 中按预期工作:

if (route.tokens[0] === "day") {
    // resolve to Day type
    route.tokens[0] === 'day'
} else if (route.tokens[0] === "landing") {
    // resolve to Landing type
    route.tokens[0] === 'landing'
} else {
    // resolve to Month type
    route.tokens[0] === 'month'
}

原创

虽然为每个联合成员编写类型保护的解决方案是完全有效的,但如果联合中有许多成员或者稍后向联合添加额外的成员,它确实会产生问题。

您可以使用 Extract 条件类型创建一个自定义类型保护来保护所有可能的类型:

type Landing = {
    tokens: ['landing']
};

type Month = {
    tokens: ['month', string]
};

type Day = {
    tokens: ['day', string, string]
};

type Route =
    | Month
    | Day
    | Landing;

declare let route: Route;

function isRoute<T extends Route['tokens'][0]>(r: Route, type: T): r is Extract<Route, { tokens: [T, ...any[]] }> {
    return route.tokens[0] === type;
}

if (isRoute(route, 'day')) {
    // resolve to Day type
    route.tokens[0] === 'day'
} else if (isRoute(route, 'landing')) {
    // resolve to Landing type
    route.tokens[0] === 'landing'
} else {
    // resolve to Month type
    route.tokens[0] === 'month'
}

Playground link

关于TypeScript:区分元组中的联合和值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53073066/

相关文章:

javascript - 当可能有两个以上的值时,初始化常量变量的更简洁的方法是什么

f# - 向 F# 可区分联合添加常量字段

reactjs - 要求至少将一个 prop 传递给组件 [typescript]

typescript - 参数,其中一个是枚举,另一个是字符串的并集,它们是该枚举的有效键

html - 使用 typescript ,如何更新 HTML 元素的值和文本。?

f# - 受歧视的工会结构/习俗平等

javascript - 如何使用 Bazel 构建 TypeScript

F#:将受歧视的联合和类层次结构结合在一起?

f#:常量联合案例标记号