TypeScript 意外地影响了基于赋值表达式中使用的右侧表达式的类型,

wa7juj8i  于 6个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(51)

Bug报告

🔎 搜索词

(所有搜索词都在标题中)

🕗 版本与回归信息

  • 在版本4.2.3和4.3.5之间发生了变化

它仍然在4.7.4、4.8-beta和当前的夜间版本(4.8.0-dev.20220712)上运行。

⏯ Playground链接

带有相关代码的Playground链接

💻 代码

type Type = string | number

let obj: Record<string, Type> = {}
function test<T extends Type>(val: T): T {
  if (0) {
    // This typechecks but is wordier than needed.
    obj['test'] = val;
    return val;
  }

  // Nice and concise, but fails type checking.
  return obj['test'] = val;
}

let string = test('hello') // should be fine

🙁 实际行为

类型检查失败。这似乎是因为表达式 obj['test'] = val 被赋予了更广泛的LHS( Type )的类型,而不是RHS( T )的更窄的类型。

🙂 预期行为

这应该能正确进行类型检查。考虑到赋值操作的RHS总是需要比LHS更窄,使用RHS似乎是最合理的选择。如果RHS是 any 的一个可能例外,可以回退到LHS。这对于与顶级代码保持一致也是很好的,因为在那里它似乎能正确工作。

zaqlnxep

zaqlnxep1#

这应该能正确进行类型检查。考虑到赋值操作符的右侧总是比左侧更窄,
这里的底层逻辑是正确的,但问题在于这通常过于具体。例如:

function fn() {
  let s: string[];
  return s = [];
}

fn 的返回类型是 string[],因为我们使用了左侧的类型。如果我们使用了右侧的类型,它将是 never[],这并不是你真正希望在程序中表现出来的类型。

fcg9iug3

fcg9iug32#

我认为它没有按照预期工作,因为我手动示例化模板并用 string 替换 T 时,它确实进行了类型检查。
我做了更多的调查,意识到我对错误原因的认识是错误的。问题不在于它使用了赋值的左侧,而是它在 func<T extends WideTemplateType> 中使用了 WideTemplateType 而不是精确的类型 T(不确定 TS 中这些术语的技术名称是什么)。这是一个更好的代码示例,与上一个Playground链接相同:

type LhsType          = string | number | null
type WideTemplateType = string | number

let obj: Record<string, LhsType> = {}
function test<T extends WideTemplateType>(val: T): T {
  if (0) {
    // This typechecks but is wordier than needed.
    obj['test'] = val;
    return val;
  }

  // Nice and consise, but fails type checking.
  return obj['test'] = val;

  let showType = obj['test'] = val
  //  ^?
  //  Should be T but is WideTemplateType instead
}

let string = test('hello') // should be fine

我应该选择 A)更新此工单的描述和摘要以反映这些新信息,B)关闭此工单并打开一个新的干净工单,还是 C)两者都不做?

z6psavjg

z6psavjg4#

问题在于,它在 func<T extends WideTemplateType> 中使用了 WideTemplateType 而不是精确的类型 T(不确定 TS 中的那些东西的技术名称是什么)。

为了将来参考:T 是一个 类型参数,而 WideTemplateType 是它的 约束条件

相关问题