繁体   English   中英

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

[英]TypeScript: Discriminate union from value in a tuple

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

例如

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
}

编辑自从原始答案以来,打字稿在区分工会方面就变得更好了,所以这在打字稿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'
}

Orignial

虽然为每个工会成员编写类型保护的解决方案是完全有效的解决方案,但是如果工会的成员很多,或者如果您以后向工会添加其他成员,则确实会产生问题。

您可以使用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'
}

游乐场链接

使用typeguards会是这样的:

type Landing = {
  tokens: ['landing']
};
const isLanding = (x: any): x is Landing => x[0] === 'landing'

type Month = {
  tokens: ['month', string]
};
const isMonth = (x: any): x is Month => x[0] === 'month'

type Day = {
  tokens: ['day', string, string]
};
const isDay = (x: any): x is Day => x[0] === 'day'

type Route =
  | Month
  | Day
  | Landing;

let route: Route = getRoute();

if(isDay (route)) {
  // resolve to Day type
}

您可以在官方文档中找到有关类型保护的更多信息(搜索类型保护)。

希望它能回答您的问题;)

TypeScript 在v4.6中添加了对解构可区分联合的控制流分析的支持。

type Action =
  | { kind: "NumberContents"; payload: number }
  | { kind: "StringContents"; payload: string };

function processAction(action: Action) {
  const { kind, payload } = action;
  if (kind === "NumberContents") {
    let num = payload * 2;
    // ...
  } else if (kind === "StringContents") {
    const str = payload.trim();
    // ...
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM