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

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

640 (5).png

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 的元素。


  1. 如果 Sourcetype 可以分配给 TargetType,那么 SourcetypeTargetType 的子集。因此,TargetType 也允许SourceType 所允许的所有值。


  1. 类型 Type1Type2Type3的联合类型是定义它们的集合在集合论中的并集。


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


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


  • 源代码有个位置,每个位置都有一个静态类型。在支持 Typescript 的编辑器中,如果我们将鼠标悬停在某个位置的上方,就可以看到该位置的静态类型。


  • 当源位置通过赋值、函数调用等方式连接到目标位置时,源位置的类型必须与目标位置的类型兼容。Typescript 规范通过所谓的类型关系定义类型的兼容性。


  • 类型关系分配兼容性定义了源类型 S 何时可以分配给目标类型 T:


  • ST 都是一样的类型


  • S 或者 T 是 any 类型。


  • 等等


让我们考虑以下问题:


  1. 如果 myVariable 的静态类型可以分配给 MyType ,那么 myVariable 就具有类型 MyType


  1. 如果 SourceTypeTargetType 是互相兼容的,那么SourceType可以分配给 TargetType


  1. 联合类型的工作方式是通过类型关系成员定义的。

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


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

目录
相关文章
|
5月前
|
JavaScript 前端开发
揭秘 TypeScript 条件类型:超越简单类型检查
揭秘 TypeScript 条件类型:超越简单类型检查
|
5月前
|
JavaScript 安全 索引
TypeScript 高级类型工具:Partial, Required, Record 的妙用与陷阱
TypeScript 高级类型工具:Partial, Required, Record 的妙用与陷阱
|
5月前
|
JavaScript 安全 IDE
TypeScript 类型体操:别让 `any` 毁了你的安全网!
TypeScript 类型体操:别让 `any` 毁了你的安全网!
|
5月前
|
JavaScript 安全 编译器
TypeScript 类型守卫:让你的类型系统更智能
TypeScript 类型守卫:让你的类型系统更智能
|
10月前
|
存储 安全 JavaScript
TypeScript-内置应用程序类型-Recode
通过使用 `Record` 类型,开发者可以显著提升代码的安全性和可维护性。无论是配置对象、字典结构还是动态表单,`Record` 类型都提供了一个简洁、类型安全的解决方案。
462 82
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
323 0
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
存储 JavaScript
typeScript进阶(11)_元组类型
本文介绍了TypeScript中的元组(Tuple)类型,它是一种特殊的数组类型,可以存储不同类型的元素。文章通过示例展示了如何声明元组类型以及如何给元组赋值。元组类型在定义时需要指定数组中每一项的类型,且在赋值时必须满足这些类型约束。此外,还探讨了如何给元组类型添加额外的元素,这些元素必须符合元组类型中定义的类型联合。
172 0
|
JavaScript 前端开发 安全
使用 TypeScript 加强 React 组件的类型安全
【10月更文挑战第1天】使用 TypeScript 加强 React 组件的类型安全
322 106
|
设计模式 JavaScript 安全
TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等
本文深入探讨了TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等,旨在帮助开发者在保证代码质量的同时,实现高效的性能优化,提升用户体验和项目稳定性。
393 6