typescript 对象不起作用的JsDoc联合类型

hgqdbh6s  于 2023-01-21  发布在  TypeScript
关注(0)|答案(3)|浏览(408)

我对这个问题束手无策。它看起来应该可以工作,我已经纠结了几个小时,但我不确定出了什么问题。这是我能想出的最小的例子。我甚至有一个类型保护。

/** @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

我得到错误:

Property 'b' does not exist on type '{ a: string; } | { b: string; }'.
  Property 'b' does not exist on type '{ a: string; }'.ts(2339)
q5lcpyga

q5lcpyga1#

编辑:这个问题的根源是我对联合运算符|和TypeScript如何缩小类型的误解。Tsserver,即类型脚本语言服务,是解释这些JSDoc注解和提供像自动完成这样的语言服务的东西。我将编写一些TypeScript来正确地解释类型在这种情况下是如何工作的。
鉴于这种情况:

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

const typeC: TypeC = { /* omitted */ };

typeC可能是TypeA或者TypeB,但是我们不知道是哪一个。TypeScript不允许我们访问typeC.atypeC.b,因为我们没有编写任何代码将typeC缩小到TypeATypeB。这就是自动完成不起作用的原因。这就是为什么在我前面的回答中,duck类型,或者使用Assert变量为TypeB的类型保护,可以工作。
因此,对于联合,您需要在运行时缩小类型范围,以便能够安全地访问属性,可能需要检查是否存在一组唯一于可能类型之一的属性,或者使用as的Assert,或者其他方法。
另一种方法是使用交集。交集表示一个类型具有两个类型的所有属性。这将起作用:

type TypeC = TypeA & TypeB;

然后我们可以访问typeC.atypeC.b
以下是我以前的回答,出于历史原因保留了下来。
我发现,如果我能够回避将TypeC类型为TypeB,jsdoc样式的类型保护允许我访问TypeC的属性。

/** @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
}

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

3wabscal

3wabscal2#

我认为你正在寻找A和B的交集,而不是并集。下面是解决你的问题的 typescript 代码:

interface A {
  a: string;
}

interface B {
  b: string;
}

type C = A & B;
xmjla07d

xmjla07d3#

当你说一个值是A或B类型时,类型脚本编译器不知道该变量引用的是哪种类型的值。

/** @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

您需要一个条件来确定typeC引用的值的实际类型。例如:

if ('a' in typeC) {
    console.log(typeC.a) // autocompletion for property a works       
} else {
    console.log(typeC.b) // autocompletion for property b works       
}

相关问题