这是TS中的一个错误吗?(插值的esliteral没有被视为字符串类型)

huangapple go评论76阅读模式
英文:

Is this a bug in TS? (interpolated esliteral not being treated as a string type)

问题

TS似乎认为插值属性值的类型,如:

{ href: `#234${undefined}2213` } 

在判定联合类型内使用时,并非字符串?

以下是第三个 p3 实例,当 href 是插值的 esliteral 字符串时,失去了对 ev 字段的类型推断。

type BiomePlainLinkProps = {
  href: string;
  onClick?: (event: string) => void;
}

type BiomeButtonProps = {
  href?: never;
  onClick?: (event: number) => void;
}

export type ClickableDiscriminatedUnion =
  | BiomePlainLinkProps
  | BiomeButtonProps;

const p1: ClickableDiscriminatedUnion = {
  href: '2332132',
  onClick: (ev) => console.log('@@@@', ev), // ev 在这里是字符串
}

const p2: ClickableDiscriminatedUnion = {
  onClick: (ev) => console.log('@@@@', ev), // ev 在这里是数字
}

const p3: ClickableDiscriminatedUnion = {
  href: `2${undefined}332132`,
  onClick: (ev) => console.log('@@@@', ev), // ev 在这里是 any(非字符串)
}
英文:

TS seems to think the type of interpolated prop values like:

{ href: `#234${undefined}2213` }

are NOT strings (when they're used inside a discriminated union)?

The third p3 instance below loses type inference for the ev field, but only when the href is an interpolated esliteral string.

type BiomePlainLinkProps = {
  href: string;
  onClick?: (event: string) => void;
}

type BiomeButtonProps = {
  href?: never;
  onClick?: (event: number) => void;
}

export type ClickableDiscriminatedUnion =
  | BiomePlainLinkProps
  | BiomeButtonProps;

const p1: ClickableDiscriminatedUnion = {
  href: '2332132',
  onClick: (ev) => console.log('@@@@', ev), // ev is string here
}

const p2: ClickableDiscriminatedUnion = {
  onClick: (ev) => console.log('@@@@', ev), // ev is number here
}

const p3: ClickableDiscriminatedUnion = {
  href: `2${undefined}332132`,
  onClick: (ev) => console.log('@@@@', ev), // ev is any (not string) here
}

TS sandbox full repro

答案1

得分: 4

更新 适用于TS5.2+

该错误已在 microsoft/TypeScript#53907 中修复,因此从 TypeScript 5.2 开始,问题中的代码将按预期运行,无需进行任何更改。

Playground链接到使用TS 5.2.0-dev.20230516的代码


原始答案 适用于TS5.1-

事实证明,是的,这是TypeScript的一个错误,如 microsoft/TypeScript#53888 中所述,我针对这个Stack Overflow问题提交了此问题。 编译器似乎承认 辨别联合类型 属性 href 的类型是 string 而不是 undefined,但这发生得太晚了,无法 上下文类型化 onClick 回调参数。 可能 模板文字插值 会延迟足够长时间,以导致此问题。

GitHub问题在 待办事项列表中,这意味着TS团队暂时没有计划修复它...但这也标记为 求助于,意味着他们将考虑社区成员的拉取请求;因此,任何想要尽快解决此问题的人都应考虑自己贡献修复。

与此同时,我建议在这里使用的解决方法是提前执行字符串插值并将其存储在 const 中,以便其类型在预先知道:

const theHref = `2${undefined}332132`;

const p4: ClickableDiscriminatedUnion = {
  href: theHref,
  onClick: (ev) => ev.toUpperCase()  // okay
}

这很烦人(在JSX中可能更烦人),但至少它能工作!

Playground链接到代码

英文:

UPDATE for TS5.2+

This bug has been fixed in microsoft/TypeScript#53907, so starting with TypeScript 5.2, the code in the question will work as desired with no changes necessary.

Playground link to code using TS 5.2.0-dev.20230516


ORIGINAL ANSWER for TS5.1-

It turns out that yes, this is a bug in TypeScript, as described in microsoft/TypeScript#53888 which I filed in response to this Stack Overflow question. The compiler seems to recognize that the discriminant property href is of type string as opposed to undefined, but this happens too late to contextually type the onClick callback parameter. Presumably template literal interpolation delays things enough to cause the problem.

The GitHub issue is in the Backlog, meaning that the TS team does not plan to fix it anytime soon... but as such it is also marked Help Wanted, meaning that they will entertain pull requests from community members; so anyone who wants to see this addressed sooner than later should consider contributing the fix themselves.

In the meantime, the workaround I'd recommend here is just to do your string interpolation ahead of time and store it in a const, so that its type is known in advance:

const theHref = `2${undefined}332132`;

const p4: ClickableDiscriminatedUnion = {
  href: theHref,
  onClick: (ev) => ev.toUpperCase()  // okay
}

It's annoying (probably more so with JSX) but at least it works!

Playground link to code

huangapple
  • 本文由 发表于 2023年4月17日 08:51:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031041.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定