# 《深入理解 TypeScript》
# 第一章 为什么要使用 TypeScript
- 为 JavaScript 提供可选的类型系统
- 兼容当前及未来的 JavaScript 的特性,是 JavaScript 的超集
# 第二章 JavaScript 常见语法
TypeScript 将试图保护你免受无意义的 JavaScript 代码的影响,关于 JavaScript 的知识仍然需要学习。
[] + []; // JavaScript 返回 '',TypeScript 会报错
{} + []; // JavaScript 返回 0,TypeScript 会报错
[] + {}; // JavaScript 返回 [object Object],TypeScript 会报错
'hello' - 1; // JavaScript 返回 NaN,TypeScript 会报错
# 相等
在 JavaScript 中:
5 == '5' // true
5 === '5' // false
"" == "0" // false
"" == 0 // true
而在 TypeScript 中在编写代码时就会报错,避免了隐式类型转换:
5 == '5' // false
5 === '5' // false
"" == "0" // false
"" == 0 // false
# null 和 undefined
- undefined:变量没有初始化
- null:变量不可用
无论在 JavaScript 还是在 TypeScript 中:
null == undefined // true
0 == undefined // false
"" == undefined // false
false == undefined // false
推荐使用 == null 来检查 undefined 和 null,因为你通常不希望区分它们。
function foo (arg: string | null | undefined) {
if (arg != null) {
// arg 是字符串的情况,因为 != 排除了 null 和 undefined
}
}
限制显示地使用 undefined
function foo() {
// if ...
return { a: 1, b: 2 }
// else ...
return { a: 1, b: undefined }
}
// 应该使用一个返回值的类型注解
function foo(): {a: number, b?: number} {
// if ...
return { a: 1, b: 2 }
// else ...
return { a: 1}
}
Json 和序列化
// JSON 标准支持编码 null,但是不支持 undefined
JSON.stringify({a: null, b: undefined}) // {a: null}
# 数字
内置数字类型表示的整数限制是
console.log({max: Number.MAX_SAFE_INTEGER, min: Number.MIN_SAFE_INTEGER})
// {max: 9007199254740991, min: -9007199254740991}
// 不安全的值会存在误差
console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2) // true
为了检查是否安全可以使用Number.isSafeInteger
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
无穷
数字的边界值可以用 Number.MAX_VALUE
和 -Number.MAX_VALUE
的值来表示
console.log(Number.MAX_VALUE) // 1.7976931348623157e+308
console.log(-Number.MAX_VALUE) // -1.7976931348623157e+308
超出边界但是精读没有改变的值都被限制在此范围内,但是超出边界且精度已经改变的值,用 Infinity 表示
console.log(Number.MAX_VALUE + 10**1000); // Infinity
最小非 0 值可以用 Number.MIN_VALUE
来表示
console.log(Number.MIN_VALUE); // 5e-324
// 小于 MIN_VALUE 的值会被转换为 0
console.log(Number.MIN_VALUE / 10); // 0
就像大于 Number.MAX_VALUE 的值会被限制为 Infinity,小于 Number.MIN_VALUE 的值会被限制为 0
# 第三章 JavaScript新语法特性
# 3.1 类
1. 继承:支持使用 extends 关键字实现单继承
2. 静态:静态属性会被所有的实例共享
class Something {
static instances = 0;
constructor() {
Something.instances++;
}
}
var s1 = new Something();
var s2 = new Something();
console.log(Something.instances); // 2
3. 访问修饰符:public、private、protected
可访问 | public | protected | private |
---|---|---|---|
类 | 是 | 是 | 是 |
子类 | 是 | 是 | 否 |
实例 | 是 | 否 | 否 |
在运行时(在编译后的 JavaScipt 代码中),这些没有任何意义,但是如果你没有正确地使用它们的话,在编译时会抛出错误。
4. 抽象:拥有一个 abstract 修饰符意味着该函数不能直接被调用,并且子类必须实现这个功能
- abstract 类不能直接被实例化,用户必须创建一个类来继承 abstract 类
- abstract 成员不能直接被访问,子类必须实现这个功能
5. 构造器:构造器是可选的,类不是必须要有一个构造器,示例如下:
class Foo {}
var foo = new Foo();
可以使用构造器来定义成员变量
class Foo {
x: number;
constructor(x: number) {
this.x = x;
}
}
// TS 为这种方式提供了一个缩写,x 加一个修饰符前缀,它会在类上自动声明,并且从构造器中复制过去
class Foo {
constructor(public x: number)
}
# 3.2 箭头函数
this 一直是 JavaScript 的一个痛点,箭头函数通过使用捕获上下文的 this 的意义的方式,修复了此问题。
function Person(age) {
this.age = age;
this.growOld = function() {
this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld, 1000);
setTimeout(function() {
console.log(person.age); // 1
}, 2000)
如果在浏览器中运行,函数中的 this 将会指向 window,利用箭头函数改写
function Person(age) {
this.age = age;
this.growOld = () => {
this.age++;
}
}
// 相当于捕获了 this
function Person(age) {
this.age = age;
var _this = this;
this.growOld = function() {
_this.age++;
}
}
var person = new Person(1);
setTimeout(person.growOld, 1000);
setTimeout(function() {
console.log(person.age); // 1
}, 2000)
快速返回对象
// 错误
var foo = () => {
bar: 123
}
// 正确
var foo = () => {
return { bar: 123 }
}
// 正确
var foo = () => ({
bar: 123
})
# 3.3 let
let 声明了块级作用域,let
关键字,创建块级作用域的条件是必须有一个 { }
包裹:
var foo = 123;
if (true) {
var foo = 456;
}
console.log(foo); // 456
// test.ts
let foo = 123;
if (true) {
let foo = 456;
}
console.log(foo); // 123
// 以上代码经过 ts 转换后会创建一个新的变量名
var foo = 123;
if (true) {
var foo_1 = 456;
}
console.log(foo);
除 let 外,函数也可以创建一个新的作用域
var foo = 123
function test() {
var foo = 456
}
test()
console.log(foo) // 123
# 3.4 rest
使用 rest 可以删除成员
const point3D = { x: 1, y: 2, z: 3 };
const { z, ...point2D } = point3D;
console.log(point2D); // { x: 1, y: 2 }
# 3.5 扩展运算符
对于对象来说,扩展的顺序很重要,后面的属性可以覆盖前面的属性。
const point2D = { x: 1, y: 2 };
const point3D = { x: 5, z: 4, ...point2D }; // { x: 1, y: 2, z: 4}