以下内容是本人在学习拉勾教育专栏《TypeScript入门实战笔记》和个人的一些实践总结
在语法层面,缺省类型注解的 TypeScript 与 JavaScript 完全一致。因此,我们可以把 TypeScript 代码的编写看作是为 JavaScript 代码添加类型注解 在 JavaScript 中,原始类型指的是非对象且没有方法的数据类型,它包括 string、number、bigint、boolean、undefined 和 symbol 这六种 (null 是一个伪原始类型,它在 JavaScript 中实际上是一个对象,且所有的结构化类型都是通过 null 原型链派生而来)。原始类型值是最底层的实现,对应到 TypeScript 中同样也是最底层的类型
字符串
在 JavaScript 中,我们可以使用string表示 JavaScript 中任意的字符串(包括模板字符串),具体示例如下所示:
let firstname: string = 'Forest'; // 字符串字面量
let familyname: string = String('C'); // 显式类型转换
let fullname: string = `my name is ${firstname}.${familyname}`; // 模板字符串
所有 JavaScript 支持的定义字符串的方法,我们都可以直接在 TypeScript 中使用
数字
同样,我们可以使用number类型表示 JavaScript 已经支持或者即将支持的十进制整数、浮点数,以及二进制数、八进制数、十六进制数,具体的示例如下所示:
/** 十进制整数 */
let integer: number = 6;
/** 十进制整数 */
let integer2: number = Number(42);
/** 十进制浮点数 */
let decimal: number = 3.14;
/** 二进制整数 */
let binary: number = 0b1010;
/** 八进制整数 */
let octal: number = 0o744;
/** 十六进制整数 */
let hex: number = 0xf00d;
如果使用较少的大整数,那么我们可以使用bigint类型来表示
let big: bigint = 100n;
::: warning
虽然number和bigint都表示数字,但是这两个类型不兼容。
:::
布尔值
使用boolean表示 true 或者 false,该值可以比较(==、===、||、&&)、可以否定(!)
/** TypeScript 真香 为 真 */
let typeScriptIsGreat: boolean = true;
/** TypeScript 太糟糕了 为 否 */
let typeScriptIsBad: boolean = false;
symbol
自 ECMAScript 6 起,TypeScript 开始支持新的Symbol原始类型, 即我们可以通过Symbol构造函数,创建一个独一无二的标记;同时,还可以使用symbol表示如下代码所示的类型
let sym1: symbol = Symbol();
let sym2: symbol = Symbol('42');
TypeScript 还包含 Number、String、Boolean、Symbol 等类型(注意区分大小写);当为大写时表示类型字面量
any
any指的是一个任意类型,是类型中的教父。为了目的它不惜一切代价,但是不要轻易请它纯棉,除非不得已;在TypeScript中,编译时一定都要有类型,如果你无法确定类型是什么,默认为any;这是个兜底类型,应该尽可能的避免使用;any类型的值就像常规的JavaScript一样,我们可以对被注解为 any 类型的变量进行任何操作,包括获取事实上并不存在的属性、方法,并且 TypeScript 还无法检测其属性是否存在、类型是否正确。类型检查器完全发挥不了作用
let anything: any = {};
anything.doAnything(); // 不会提示错误
anything = 1; // 不会提示错误
anything = 'x'; // 不会提示错误
let num: number = anything; // 不会提示错误
let str: string = anything; // 不会提示错误
any 类型会在对象的调用链中进行传导,即所有 any 类型的任意属性的类型都是 any
let anything: any = {};
let z = anything.x.y.z; // z 类型是 any,不会提示错误
z(); // 不会提示错误
unknown
unknown类型,它主要用来描述类型并不确定的变量;unknown类型的值可以比较、可以否定、可以使用JavaScript的typeof和instanceof运算符细化
比如在多个 if else 条件分支场景下,它可以用来接收不同条件下类型各异的返回值的临时变量,如下代码所示:
let result: unknown;
if (x) {
result = x();
} else if (y) {
result = y();
} ...
与 any 不同的是,unknown 在类型上更安全。比如我们可以将任意类型的值赋值给 unknown,但 unknown 类型的值只能赋值给 unknown 或 any,如下代码所示:
let result: unknown;
let num: number = result; // 提示 ts(2322)
let anything: any = result; // 不会提示错误
使用 unknown 后,TypeScript 会对它做类型检测。但是,如果不缩小类型(Type Narrowing),我们对 unknown 执行的任何操作都会出现如下所示错误:
let result: unknown;
result.toFixed(); // 提示 ts(2571)
而所有的类型缩小手段对 unknown 都有效,如下代码所示:
let result: unknown;
if (typeof result === 'number') {
result.toFixed(); // 此处 hover result 提示类型是 number,不会提示错误
}
void、undefined、null
void 类型,它仅适用于表示没有返回值的函数。即如果该函数没有返回值,那它的类型就是 void。在 strict 模式下,声明一个 void 类型的变量几乎没有任何实际用处,因为我们不能把 void 类型的变量值再赋值给除了 any 和 unkown 之外的任何类型变量。
undefined 类型 和 null 类型,它们是 TypeScript 值与类型关键字同名的唯二例外
let undeclared: undefined = undefined;
let nullable: null = null;
undefined 的最大价值主要体现在接口类型上,它表示一个可缺省、未定义的属性。
我们可以把 undefined 值或类型是 undefined 的变量赋值给 void 类型变量,反过来,类型是 void 但值是 undefined 的变量不能赋值给 undefined 类型。
const userInfo: {
id?: number;
} = {};
let undeclared: undefined = undefined;
let unusable: void = undefined;
unusable = undeclared; // ok
undeclared = unusable; // ts(2322)
除此之外,undefined 和 null 类型还具备警示意义,它们可以提醒我们针对可能操作这两种(类型)值的情况做容错处理。也就是在操作之前判断值的类型是否支持当前的操作,类型守卫既能通过类型缩小影响 TypeScript 的类型检测,也能保障 JavaScript 运行时的安全性,如下代码所示:
const user: {
id?: number;
name?: null | string
} = { id: 1, name: 'Captain' };
if (userInfo.id !== undefined) {
userInfo.id.toFixed(); // id 的类型缩小成 number
}
我们可以使用非空断言来排除值可能为 null 或 undefined 的情况,但是这样很不安全。
userInfo.id!.toFixed();
userInfo.name!.toLowerCase()
而比非空断言更安全、类型守卫更方便的做法是使用单问号(Optional Chain)、双问号(空值合并),我们可以使用它们来保障代码的安全性,如下代码所示:
userInfo.id?.toFixed(); // Optional Chain
const myName = userInfo.name?? `my name is ${info.name}`; // 空值合并
never
never 表示永远不会发生值的类型
function ThrowError(msg: string): never {
throw Error(msg);
}
以上函数因为永远不会有返回值,所以它的返回值类型就是 never。
never 是所有类型的子类型,它可以给所有类型赋值;但是反过来,除了 never 自身以外,其他类型(包括 any 在内的类型)都不能为 never 类型赋值。
let Unreachable: never = 1; // 报错
Unreachable = 'string'; // 报错
Unreachable = true; // 报错
let num: number = Unreachable; // ok
let str: string = Unreachable; // ok
let bool: boolean = Unreachable; // ok