TS2339:交替类型无法识别属性

时间:2021-04-04 22:11:58

标签: typescript

type NotifyOptions = {
    className: string
    timeout?: null | number
} & ({ text: string } | { html: string })


export default function notify(options: NotifyOptions) {
  if(options.text) {
    console.log(options.text)
  }
}
<块引用>

“NotifyOptions”类型上不存在属性“text”。 类型“{ className: string;”上不存在属性“text”超时?:数字 |空|不明确的; } & { html: 字符串; }'.(2339)

ts playground

为什么说 options.text 不存在?我认为它应该输入为 string|undefined

2 个答案:

答案 0 :(得分:2)

This playground 展示了一个允许“歧视联合”的工作示例。它的工作方式是使用 Typescript 可以实际利用的检查类型(字面相等)来分离特定类型。见discriminated unions

type NotifyOptions = {
  className: string;
  timeout?: null | number;
} & ({
  kind: "html";
  html: string;
}|{
  kind: "text";
  text: string;
});

export default function notify(options: NotifyOptions) {
  if (options.kind === "text") {
    console.log(options.text);
  }
  else if(options.kind === "html") {
    console.log(options.html);
  }
}

不幸的是,typescript 的工作方式是,您只能引用在所有联合情况下都存在的属性。因此需要有一个 kind 属性。你可以在 https://stackoverflow.com/a/65495776/2257198

上看到 jcalz 什么时候教我的

如果您的案例真的可以不注意类型系统(例如,您只对属性的存在感兴趣并且能够取消引用它而不管其类型如何),那么对原始代码的最小更改是使用 in 运算符,它消除了这样的编译器错误。

export default function notify(options: NotifyOptions) {
  if("text" in options) {
    console.log(options.text)
  }
}

如果您不关心您的案例的 Typescript 类型,您可以更深入地使用 javascript 打字路线...

export default function notify(options: NotifyOptions) {
  if("text" in options && typeof options.text === "string") {
    console.log(options.text)
  }
}

答案 1 :(得分:2)

Typescript 将只允许您访问联合的每个成员共有的属性。

另一方面,它不允许您访问仅在联合的一个成员中定义的属性。

存在于联合的一个成员上的成员在其他成员中不存在的假设在实践中可能不正确:可能存在,并且属性的类型可能不同。 因此,假设 options.text 是 string 或 undefined 被认为是不安全的。

考虑以下示例:

const o = {
    className: 'c1',
    timeout: 3000,
    html: 'ht',
    text: 4
};
const opt: NotifyOptions = o;

我创建了一个 NotifyOptions,其中文本是一个数字。

Typescript 3.2 引入了 Non-unit types as union discriminants

<块引用>

TypeScript 3.2 通过放宽其判别属性的规则,使缩小范围变得更容易。联合的公共属性现在被视为判别式,只要它们包含某种单例类型(例如字符串文字、空值或未定义),并且它们不包含泛型。

你可以写:


type NotifyOptions = {
    className: string
    timeout?: null | number
} & ({ text: string; html?: undefined; } 
   | { html: string; text?: undefined})

Typescript 允许您访问属性并将它们视为联合的判别式。

最重要的是,不再允许将 o 常量分配给 NotifyOptions。

Playground link