<Programming with Types>随想: Chapter 2. Basic types

类型限制了一个变量可以接受的有效值的集合,对数据可以进行的操作,数据的意义。
空类型(The empty type)
根据类型的定义,类型定义了可以接受的有效值集合,那么这个集合有没有可能为空?答案是有可能的,TypeScirpt 的 never 就是这种类型。
需要注意的是,空类型不同与 void, 后者是有效值集合当中只有一个值,但这个值没有任何意义。而空类型的有效值集合本身是空的。
使用场景
控制流分析
在函数调用时,标志一个函数不会返回任何值: 在调用过程中抛出异常、死循环或者程序崩溃。即返回值类型为 never 的函数,不会将CPU的控制权返回给被调函数。
function raise(message: string): never {
throw new Error(message);
}
function forever(): never {
while (true) {}
}
如果返回实际的值或者在调用处后面的继续编写代码逻辑,会引起编译错误。
function main() {
forever()
console.log(1); // Unreachable code detected.(7027)
}
ADT 的 Exhaustive(穷尽) Check
当业务中有一个 union type
interface Foo {
type: 'foo'
}
interface Bar {
type: 'bar'
}
type All = Foo | Bar
在 switch 当中判断 type,TS 是可以收窄类型的 (discriminated union):
function handleValue(val: All) {
switch (val.type) {
case 'foo':
// 这里 val 被收窄为 Foo
break
case 'bar':
// val 在这里是 Bar
break
default:
// val 在这里是 never
const exhaustiveCheck: never = val
break
}
}
注意在 default 里面我们把被收窄为 never 的 val 赋值给一个显式声明为 never 的变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事改了 All 的类型:
type All = Foo | Bar | Baz
然而他忘记了在 handleValue 里面加上针对 Baz 的处理逻辑,这个时候在 default branch 里面 val 会被收窄为 Baz,导致无法赋值给 never,产生一个编译错误。所以通过这个办法,你可以确保 handleValue 总是穷尽 (exhaust) 了所有 All 的可能类型。
参考链接:https://www.zhihu.com/question/354601204
类型运算
never 是任何类型的 subtype(子类型), 除了never,没有其他类型是never的subtype。
这个例子体现 never 的取值有效集是空集,在 TS 中,可以对类型做集合的交并运算。 never 是 union(并集) 运算的幺元,intersection(交集)运算的零元.
T | never // 结果为T
T & never // 结果为never
单元类型(unit type)
单元类型的取值有效集集合中,只有一个值, 因此编译器不需要处理单元类型的具体值。
常见的单元类型有
// undefined类型。
let a: undefined = undefined;
// null类型。
let b: null = null;
// unique symbol类型。
const c: unique symbol = Symbol();
// void类型。
let d: void = undefined;
// 字面量类型。
const e: 'hello' = 'hello';
// 联合枚举成员类型。
enum Foo { A, B }
const f: Foo.A = Foo.A;
也有人认为 void is not a unit type in TypeScript
使用场景
当一个函数返回值为单元类型时,这个值没有任何含义,因为无论函数内部发生什么,正常执行都会返回这个类型,并且只有该类型只有一个值。
这种没有返回任何有意义值的函数,通常被称为actions 或者 consumers, 他们存在的目的是为了产生副作用,对现实世界产生影响,例如 console.log()
Boolean类型
boolean 类型存在短路逻辑,如果第一个操作数(operand)提供了足够的信息评估(evaluate)整个表达式,那么第二个操作数就不会被 evaluate.
数字类型
基础的二进制编码,补码,IEEE754方式,此处略去。
编码字符串
Unicode编码有几个相似但是截然不同的概念:
字符(Characters): 文本的计算机表示, 警官emoji(👮),零宽字符,女性标志(🚺)都是字符。字符这个词在不同的上下文环境中经常会被赋予不同的意思。字位(graphemes): 用户看到的符号,在渲染文本时,我们使用的是字位(graphemes),我们不想把一个多字的字位(multiple-character grapheme)拆开。glygh(字形): "字形 "是一个字符的特殊表现形式。"C"(粗体)和 "C"(斜体)是 "C "字的两种不同的视觉表现形式。code point(码点)是文本信息的原子单位。文本是一连串的代码点。每个代码点是一个数字,由Unicode标准赋予其意义。code unit(码元)编码组成code point(码点)的一部分. In UTF-8 this means 8 bits, in UTF-16 this means 16 bits. A single code unit may represent a full code point, or part of a code point. For example, the snowman glyph (☃) is a single code point but 3 UTF-8 code units, and 1 UTF-16 code unit.
长度可变的编码方式
UTF-32 是一种长度不可变的字符串编码方式,对于每一个grapheme都使用,32bit存储,但是会造成格外的空间浪费。
UTF-8 和 UTF-16 是长度可变的编码方式(variable-length encodings).



