【问题标题】:Why does an array 'extend' a readonly array in TypeScript?为什么数组在 TypeScript 中“扩展”只读数组?
【发布时间】:2022-10-07 02:23:45
【问题描述】:

TypeScript 支持条件类型,使用 \'extends\' 关键字和三元运算符。

eval 为 true 的示例条件类型:

type C1 = 7 extends number ? true : false
type C2 = 7 extends number | string ? true : false
type C3 = 7 extends 7 | \'cat\' | null ? true : false
type C4 = [1,2,3] extends [1,2,3] ? true : false
type C5 = any[] extends any[] ? true : false

我理解上述条件(即使 \'extends\' 在非 OOP 上下文中看起来很奇怪)。

以下条件我不明白:

type Q1 = any[] extends readonly any[] ? true : false  // evals to true
type Q2 = readonly any[] extends any[] ? true : false  // evals to false

为什么 Q1 评估为真,而 Q2 评估为假?我的预期正好相反,因为只读数组似乎比一般数组“更具体”。

在这种情况下,“扩展”的真正含义是什么?

我正在使用TypeScript Playground 来测试这些条件。

  • 是的,readonly 是一种具有误导性的术语。说onlyKnownToBeReadableAndMayOrMayNotBeWritable 会更准确,但没有人愿意处理这个问题。

标签: typescript


【解决方案1】:

extends 表示“是的子类型”。不多也不少。而“A 是B 的子类型”意味着“A 的每个实例都可以分配给B 类型的变量”。同样,不多也不少。

所以我们唯一需要问的问题是:T[] 是否可以分配给readonly T[]?好吧,readonly T[] 允许我们访问数组的元素。 T[] 允许我们访问数组的元素和还变异它。所以T[] 支持readonly T[] 的所有操作,然后是一些。因此,关系成立。

【讨论】:

  • 您的措辞是正确的,尽管最好说 extends 表示“可分配给”,因为 1)将变量分配给类型时,它是相同的术语和行为,以及 2)有些类型具有奇怪的行为,例如 @987654333 @ 不完全是左侧的子类型,但仍然通过 extends 子句和 any 给出两个条件分支的联合。
  • @sno2 好点。更新了措辞,使其更加清晰。我习惯了像 Scala 这样的名义语言,它实际上是一种子类型关系。但严格来说,Typescript 并非如此。
  • @sno2 你为什么说“never 不完全是一个子类型”?它是 TypeScript 中的底层类型,因此是每种类型的子类型(就像空集是每个集合的子集一样)。
  • @jcalz 现在实际上更有意义了。我原以为这只是对never 的特殊处理,但是当涉及到工会急切减少和忽略never 的行为时,将其作为最低类型确实很有意义,除非它是唯一剩下的东西。
  • 答案对我来说也没有意义。使用相同的可读和可变概念: // 预期行为类型 A = '可读'|'mutable' 扩展 '可读' ?真假; // false type C = '可读' 扩展 '可读'|'mutable' ?真假; // true // 后向行为类型 B = Array<any> extends ReadonlyArray<any> ?真假; // true type D = ReadonlyArray<any> extends Array<any> ?真假; // 错误的
【解决方案2】:

这绝对是令人困惑的。

预期行为

type A = 'readable'|'mutable' extends 'readable' ? true : false; // false
type B = 'readable' extends 'readable'|'mutable' ? true : false; // true

我理解的方式是遍历分配事物。

const C = [1]; // inferred as Array<number>
const D:ReadonlyArray<number> = C; // declare that the mutable array is readonly
const E:Array<number> = D; // error when assigning a ReadonlyArray to Array.  

该错误似乎是任意的。可能是 K 不能分配给 ReadonlyArray。

我的猜测是,由于解析器中的历史代码,他们选择了它。在解析带有const F:ReadonlyArray&lt;number&gt; = [1] 之类的文件时,[1] 可能首先被推断为 Array。他们需要一种将已经推断出的可变数组声明为只读的方法。因此,Array 可分配给 ReadonlyArray。

这是有道理的,尽管感觉像是绕过重写解析器的捷径。

【讨论】:

    猜你喜欢
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 2021-10-17
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多