gpt4 book ai didi

typescript - 细化标记联合的类型

转载 作者:行者123 更新时间:2023-12-04 15:20:12 25 4
gpt4 key购买 nike

我正在尝试编写一个将返回标记联合值的函数,但我希望根据标记改进返回类型。例如,

type Token = {kind: "+"} | {kind: "var", text: string};

let tokens: Token[] = [{kind: "var", text: "x"}, {kind: "+"}, {kind: "var", text: "y"}];

function pullToken<Kind extends Token["kind"]>(kind: Kind): Extract<Token, {kind: Kind}> {
let token = tokens.shift();
if (typeof token === "undefined" || token.kind !== kind) {
throw "oops";
}
return token;
}

let token = pullToken("var");
console.log(token.text);

给我以下错误

TS2322: Type 'Token' is not assignable to type 'Extract<{ kind: "+"; }, { kind: Kind; }> | Extract<{ kind: "var"; text: string; }, { kind: Kind; }>'.
Type '{ kind: "+"; }' is not assignable to type 'Extract<{ kind: "+"; }, { kind: Kind; }> | Extract<{ kind: "var"; text: string; }, { kind: Kind; }>'.
Type '{ kind: "+"; }' is not assignable to type 'Extract<{ kind: "var"; text: string; }, { kind: Kind; }>'.

我希望 token 可以根据 if 语句中的条件进行细化,但事实并非如此。有办法实现吗?

最佳答案

TypeScript 中的一个已知问题是您不能使用控制流分析来缩小泛型类型参数(参见 microsoft/TypeScript#24085)或类型取决于泛型类型参数的值(参见 microsoft/TypeScript#13995)。

一般来说,如果你有一个联合类型的值(比如 Token )并对其执行类型保护,那么编译器将使用 control flow analysis将该值的表观类型缩小为原始联合的某些成员或成员(如 {kind: "var", text: string} )。当值是非泛型类型时,一切都很好。

但是,如果您的值(如 token)是一种依赖于约束为联合的泛型类型参数的类型(如 Kind extends Token),则这不会发生。它不会缩小值的类型,绝对不会缩小类型参数(如 Kind)本身。

这是一个很难解决的问题,因为在很多情况下,编译器缩小类型参数的范围是不正确的,即使它可能是正确的,也需要编译器花费更多时间来执行一些高阶类型分析。也许最终语言会让你的代码“工作”。现在,您需要解决它。


编译器无法验证 token类型为 Extract<Token, {kind: Kind}> .但是您已经编写了应该(我希望)实现这一点的代码。因为你知道一些编译器不知道的关于 token 类型的事情, 你可以使用 type assertion就这么说吧:

return token as Extract<Token, {kind: Kind}>;

这将使错误消失。请注意,在 pullToken() 的实现中验证类型安全的负担现在在你身上;如果你犯了一个错误或谎言(例如,return {kind: "+"} as Extract<Token, {kind: Kind}>;,编译器将不会捕捉到它。所以要小心。


Playground link

关于typescript - 细化标记联合的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63477784/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com