从两个角度看 Typescript 中的类型是什么?

0. 作者以及原文介绍
作者是 Dr. Axel Rauschmayer,号称”德国阮一峰“,本文原文来自于他的博客:https://2ality.com/2020/02/understanding-types-typescript.html,不熟悉他的可以关注一下他的博客。
以下是原文:
1. 每个角度都从这三个问题来解释
以下三个问题对于理解类型是如何工作的非常重要,需要从这两个角度中的每一个角度来回答。
- myVariable的类型- MyType意味着什么?
let myVariable: MyType = /*...*/;
- Sourcetype可以分配给- TargetType吗?
let source: SourceType = /*...*/;
let target: TargetType = source;
- TypeUnion是如何从- Type1、- Type2和- Type3衍生而来的?
type TypeUnion = Type1 | Type2 | Type3;
2. 角度 1:类型是一组值
从这个角度来看,类型是一组值:
- 如果 - myVariable具有- MyType类型,这意味着可以分配给- myVariable的所有值都必须是集合- MyType的元素。
- 如果 - Sourcetype可以分配给- TargetType,那么- Sourcetype是- TargetType的子集。因此,- TargetType也允许- SourceType所允许的所有值。
- 类型 - Type1、- Type2和- Type3的联合类型是定义它们的集合在集合论中的并集。
3. 角度 2:类型兼容关系
从这个角度来看,我们不关心值以及它们在执行代码时如何流动。相反,我们采取了一种更为静态的观点:
- 源代码有个位置,每个位置都有一个静态类型。在支持 Typescript 的编辑器中,如果我们将鼠标悬停在某个位置的上方,就可以看到该位置的静态类型。 
- 当源位置通过赋值、函数调用等方式连接到目标位置时,源位置的类型必须与目标位置的类型兼容。Typescript 规范通过所谓的类型关系定义类型的兼容性。 
- 类型关系分配兼容性定义了源类型 - S何时可以分配给目标类型- T:
- S和- T都是一样的类型
- S或者- T是 any 类型。
- 等等 
让我们考虑以下问题:
- 如果 - myVariable的静态类型可以分配给- MyType,那么- myVariable就具有类型- MyType
- 如果 - SourceType和- TargetType是互相兼容的,那么- SourceType可以分配给- TargetType
- 联合类型的工作方式是通过类型关系成员定义的。 
类型系统一个有趣的特点是,同一个变量在不同的位置可以有不同的静态类型:
const arr = [];
// %inferred-type: any[]
arr;
arr.push(123);
// %inferred-type: number[]
arr;
arr.push('abc');
// %inferred-type: (string | number)[]
arr;
4. 标准类型系统和结构类型系统
静态类型系统的职责之一是确定两个静态类型是否兼容:
- 实际参数的静态类型 U(例如,通过函数调用提供) 
- 对应形式参数的静态类型 T(指定为函数定义的一部分) 
这通常意味着要检查 U 是否是 T 的子类型。这种检查的两种方法(大致)是:
- 在标准类型中,如果两个静态类型具有相同的标识(“名称”) ,则它们是相等的。一种类型是另一种类型的子类型,它们的子类型关系是显式声明的。 - 具有标准类型的语言有 c++ 、 Java、 c# 、 Swift 和 Rust 
- 在结构类型系统中,如果两个静态类型具有相同的结构(如果它们的部分具有相同的名称和相同的类型) ,则它们是相等的。如果 U 包含 T 的所有部分(可能还包括其他部分) ,并且 U 的每个部分都包含 T 的相应部分的子类型,那么一种类型 U 就是另一种类型 T 的子类型。 - 具有结构类型的语言有 ocaml/reasonml、 Haskell 和 TypeScript 
下面的代码在标准类型系统中产生类型错误(第 A 行) ,但在 Typescript 的结构类型系统中是合法的,因为类 A 和类 B 具有相同的结构:
class A {
  name = 'A';
}
class B {
  name = 'B';
}
const someVariable: A = new B(); // (A)
Typescript 的接口在结构上也能工作——它们不需要实现来匹配:
interface Point {
  x: number;
  y: number;
}
const point: Point = {x: 1, y: 2}; // OK
5. 进一步阅读
- Chapter “Type Compatibility” in the TypeScript Handbook[1] 
- Section “TypeRelationships” in the TypeScript Specification[2] 
如果翻译得不对的地方希望您可以帮忙指出来。
参考资料
Chapter “Type Compatibility” in the TypeScript Handbook: https://www.typescriptlang.org/docs/handbook/type-compatibility.html
[2]Section “TypeRelationships” in the TypeScript Specification: https://github.com/microsoft/TypeScript/blob/master/doc/spec.md#311-type-relationships
最后
如果你觉得这篇内容对你挺有启发,我想邀请你帮我三个小忙:
- 点个「在看」,让更多的人也能看到这篇内容(喜欢不点在看,都是耍流氓 -_-) 
- 欢迎加我微信「qianyu443033099」拉你进技术群,长期交流学习... 
- 关注公众号「前端下午茶」,持续为你推送精选好文,也可以加我为好友,随时聊骚。 

