gpt4 book ai didi

typescript - 为什么 TypeScript 数组是协变的?

转载 作者:行者123 更新时间:2023-12-04 12:19:41 25 4
gpt4 key购买 nike

TypeScript 允许我们使用父类(super class)型的变量(TypeScript 数组是协变的)为数组类型的变量添加别名:

const nums: number[] = [];
const things: (number | string)[] = nums;
things.push("foo");
nums[0] *= 3;
console.log(nums[0]); // `NaN` !!

为什么?这似乎是保护我们免受运行时错误的好地方。鉴于 Java 因具有协变数组而被 mock ,这似乎是一个有意的 TS 功能。

This was asked by someone else on a stale TypeScript issue, but I didn't see any answers.

最佳答案

正如您所指出的,数组协方差是不合理的,可能会导致运行时出错。 TypeScript's Design Non-Goals之一是

  1. Apply a sound or "provably correct" type system. Instead, strike a balance between correctness and productivity.

这意味着如果某些不健全的语言功能非常有用,并且如果要求健全性会使语言使用起来非常困难或令人讨厌,那么尽管存在潜在的陷阱,它很可能会保留下来。
显然有一点是 "a fool's errand"尝试在主要目的是描述 JavaScript 的语言中保证健全性。

我想说这里的根本问题是 TypeScript 想要支持一些非常有用的功能,不幸的是,这些功能一起玩起来很糟糕。
第一个是 subtyping ,其中类型形成层次结构,单个值可以是多种类型。如果一个类型 S是类型 T 的子类型,然后是一个值 s类型 S也是 T 类型的值.例如,如果您有一个类型为 string 的值,那么您也可以将其用作 string | number 类型的值(因为 string 是任何 string | XX 的子类型)。 TypeScript 中的整个接口(interface)和类层次结构都建立在子类型的概念上。当 S extends TS implements T , 表示 ST 的子类型.如果没有子类型,TypeScript 将更难使用。
第二个是 aliasing ,您可以使用多个名称引用相同的数据,而不必复制它。 JavaScript 允许: const a = {x: ""}; const b = a; b.x = 1; .除了原始数据类型,JavaScript 值都是引用。如果您尝试在不传递引用的情况下编写 JavaScript,那将是一种非常不同的语言。如果 TypeScript 强制要求将对象从一个命名变量传递到另一个变量,您必须复制它的所有数据,那么它会更难使用。
第三个是 mutability . JavaScript 中的变量和对象通常是可变的;您可以重新分配变量和对象属性。不可变语言更容易推理/更干净/更优雅,但改变事物很有用。 JavaScript 不是一成不变的,因此 TypeScript 允许它。如果我有一个值 const a: {x: string} = {x: "a"}; ,我可以跟进 a.x = "b";没有错误。如果 TypeScript 要求所有别名都是不可变的,那么它会更难使用。
但是将这些功能放在一起,事情可能会变糟:
let a: { x: string } = { x: "" }; // subtype
let b: { x: string | number }; // supertype
b = a; // aliasing
b.x = 1; // mutation
a.x.toUpperCase(); // 💣💥 explosion
Playground link to code
有些语言通过要求 variance 来解决这个问题。标记。 Java的 wildcards服务于这个目的,但正确使用它们相当复杂,并且(据传闻)被认为是烦人和困难的。
尽管 suggestions to the contrary,TypeScript 决定在此处不做任何事情并将所有属性类型视为协变。 .在这方面,生产力高于正确性。

出于类似原因,检查了函数和方法参数 bivariantly直到 TypeScript 2.6 引入了 --strictFunctionTypes 编译器选项,此时只有方法参数仍然总是双变量检查。
双变量类型检查是不健全的。但它很有用,因为它允许突变、别名和子类型化(不会因为要求开发人员跳过障碍而损害生产力)。 方法参数双方差导致 TypeScript 中的数组协方差 .

好的,希望有帮助;祝你好运!

关于typescript - 为什么 TypeScript 数组是协变的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60905518/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com