JsDoc 联合类型与对象不起作用

Dyl*_*dry 8 javascript jsdoc typescript

我对此无计可施。看起来它应该可以工作,我已经为此奋斗了几个小时,但我不确定出了什么问题。这是我能想到的最小的例子。我什至有一个类型保护程序。

/** @typedef {{ a: string }} TypeA*/
/** @typedef {{ b: string }} TypeB*/
/** @typedef {(TypeA | TypeB) } TypeC */

/** @type {TypeC} */
let typeC;

console.log(typeC.b) // autocompletion for property b doesn't work
Run Code Online (Sandbox Code Playgroud)

我收到错误:

Property 'b' does not exist on type '{ a: string; } | { b: string; }'.
  Property 'b' does not exist on type '{ a: string; }'.ts(2339)
Run Code Online (Sandbox Code Playgroud)

Dyl*_*dry 8

编辑:这个问题的根源是我对 union 运算符|以及 TypeScript 如何缩小类型的误解。Tsserver(打字稿语言服务)负责解释这些 JSDoc 注释并提供自动完成等语言服务。我将编写一些 TypeScript 来正确解释类型在这种情况下如何工作。

鉴于这种情况:

type TypeA = { a: string };
type TypeB = { b: string };
type TypeC = TypeA | TypeB;

const typeC: TypeC = { /* omitted */ };
Run Code Online (Sandbox Code Playgroud)

typeC可能是TypeATypeB,但我们不知道是哪一个。因此,TypeScript 不会让我们访问typeC.aor ,typeC.b因为我们还没有编写任何缩小typeCTypeAor 的代码TypeB。这就是自动完成功能不起作用的原因。这就是为什么在我之前的回答中,鸭子类型或使用断言变量 is 的类型保护TypeB有效。

因此,使用union 时,您需要在运行时缩小该类型的范围,以便能够安全地访问属性。可能通过检查是否存在对其中一种可能类型唯一的一组属性,或者使用 的断言as,或其他方式。

另一种方法是使用交集。交集表示一种类型具有两种类型的所有属性。这会起作用:

type TypeC = TypeA & TypeB;
Run Code Online (Sandbox Code Playgroud)

然后我们就可以访问typeC.atypeC.b

以下是我之前的回答,由于历史原因保留。


我发现 jsdoc 风格的类型保护可以让我访问 TypeC 的属性,如果我能够将其类型设置为 TypeB。

/** @typedef {{ a: string }} TypeA*/
/** @typedef {{ b: string }} TypeB*/
/** @typedef {(TypeA | TypeB) } TypeC */

/**
 * @param {*} value
 * @returns {value is TypeB}
 */
function typeIsB(value) {
  return true;
}

/** @type {TypeC} */
let typeC;

if (typeIsB(typeC)) {
  console.log(typeC.b) // no error, autocomplete works when typing typeC.b
}

Run Code Online (Sandbox Code Playgroud)

自动完成工作的屏幕截图:

在此输入图像描述