专栏首页前端桃园从两个角度看 Typescript 中的类型是什么?

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

0. 作者以及原文介绍

作者是 Dr. Axel Rauschmayer,号称”德国阮一峰“,本文原文来自于他的博客:https://2ality.com/2020/02/understanding-types-typescript.html,不熟悉他的可以关注一下他的博客。

以下是原文:

1. 每个角度都从这三个问题来解释

以下三个问题对于理解类型是如何工作的非常重要,需要从这两个角度中的每一个角度来回答。

  1. myVariable 的类型 MyType 意味着什么?
let myVariable: MyType = /*...*/;
  1. Sourcetype 可以分配给 TargetType 吗?
let source: SourceType = /*...*/;
let target: TargetType = source;
  1. TypeUnion 是如何从Type1Type2Type3 衍生而来的?
type TypeUnion = Type1 | Type2 | Type3;

2. 角度 1:类型是一组值

从这个角度来看,类型是一组值:

  1. 如果 myVariable 具有 MyType 类型,这意味着可以分配给 myVariable 的所有值都必须是集合 MyType 的元素。
  2. 如果 Sourcetype 可以分配给 TargetType,那么 SourcetypeTargetType 的子集。因此,TargetType 也允许SourceType 所允许的所有值。
  3. 类型 Type1Type2Type3的联合类型是定义它们的集合在集合论中的并集。

3. 角度 2:类型兼容关系

从这个角度来看,我们不关心值以及它们在执行代码时如何流动。相反,我们采取了一种更为静态的观点:

  • 源代码有个位置,每个位置都有一个静态类型。在支持 Typescript 的编辑器中,如果我们将鼠标悬停在某个位置的上方,就可以看到该位置的静态类型。
  • 当源位置通过赋值、函数调用等方式连接到目标位置时,源位置的类型必须与目标位置的类型兼容。Typescript 规范通过所谓的类型关系定义类型的兼容性。
  • 类型关系分配兼容性定义了源类型 S 何时可以分配给目标类型 T:
    • ST 都是一样的类型
    • S 或者 T 是 any 类型。
    • 等等

让我们考虑以下问题:

  1. 如果 myVariable 的静态类型可以分配给 MyType ,那么 myVariable 就具有类型 MyType
  2. 如果 SourceTypeTargetType 是互相兼容的,那么SourceType可以分配给 TargetType
  3. 联合类型的工作方式是通过类型关系成员定义的。

类型系统一个有趣的特点是,同一个变量在不同的位置可以有不同的静态类型:

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++Javac#SwiftRust
  • 在结构类型系统中,如果两个静态类型具有相同的结构(如果它们的部分具有相同的名称和相同的类型) ,则它们是相等的。如果 U 包含 T 的所有部分(可能还包括其他部分) ,并且 U 的每个部分都包含 T 的相应部分的子类型,那么一种类型 U 就是另一种类型 T 的子类型。 具有结构类型的语言有 ocaml/reasonmlHaskellTypeScript

下面的代码在标准类型系统中产生类型错误(第 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]

如果翻译得不对的地方希望您可以帮忙指出来。

参考资料

[1]

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

本文分享自微信公众号 - 前端桃园(fetaoyuan),作者:桃翁

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-03-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 通俗的方式理解动态类型,静态类型;强类型,弱类型

    桃翁
  • 你可能不知道的 21 个 Web API

    本文列举了一些列比较不常见的Web API,内容较多,所以有关兼容性的内容在本文不会出现,大家可以自己去查阅。以下案例能配动图的我尽量去配了,以免内容枯草乏味,...

    桃翁
  • 2019 TWeb 腾讯前端技术大会精彩回顾

    讲师先是介绍了 flutter, 接着讲了腾讯企鹅辅导上的实践, 包括了安卓, iOS 和 Pad 上的原生应用如何嵌入 flutter 以及原生页面与 flu...

    桃翁
  • [程序设计语言]-[核心概念]-04:数据类型

    0. 概述 为何高级语言需要类型系统这个概念?在汇编时代是没有完整的数据类型系统的,结构化编程引入了结构化的控制流、为结构化设计的子程序,随之这种结构化的代码所...

    blackheart
  • Go语言实战笔记(七)| Go 类型

    Go 语言是一种静态类型的编程语言,所以在编译器进行编译的时候,就要知道每个值的类型,这样编译器就知道要为这个值分配多少内存,并且知道这段分配的内存表示什么。

    飞雪无情
  • 效率编程 之「泛型」

    每种泛型都定义了一组参数化类型,其构成格式为:先是类或者接口的名称,接着用尖括号(<>)把对应于泛型形式类型参数的实际类型参数列表括起来。例如,List<Str...

    CG国斌
  • Go语言核心编程(3)——类型系统

    注:本文是《Go语言核心编程》(李文塔/著)个人读书笔记 命名类型(Named Type) 类型可以通过标识符来表示,这种类型称为命名类型。Go 语言的基本...

    羊羽shine
  • 八、通用类型系统

    1、通用类型简介         CLR中的一切都围绕类型展开,因为IL是面向对象的高级机器语言.类型向应用程序和其他类型公开了功能.通过类型,用一种编程语言写...

    郑小超.
  • go 参数传递

    http://stor.51cto.com/art/201712/559955.htm go 中都是值传递的,即使是map、切片这些。 只不过类型分为:

    平凡的学生族
  • Golang学习笔记 数据类型和变量

    数据类型 先来介绍一下Golang的数据类型。 布尔型 bool类型代表逻辑值,有真值true和假值false两种取值。 整数类型 整数类型有如下几种,这些整数...

    乐百川

扫码关注云+社区

领取腾讯云代金券