TypeScript
js 与 ts 的关系
1.js本身没有对变量、函数参数进行类型限制;
2.这样虽然灵活但是也有安全隐患;
3.之后facebook 推出了 flow,微软推出了 ts,他们都是致力于为 js 提供类型检查,而不是取代;
4.并且在ts 的官方文档上有这么一句话:源于 js,归于 js!;
5.最终ts还是需要转换成 js 代码才能运行的;
6.当然不排除有一天 js 本身也会加入类型检测,那么无论是 ts 还是 flow 都有可能因此退出历史舞台;
型检测
共识
错误 出现的越早越好
能在写代码时发现错误,就不要再代码编译时再发现(IDE的优势就是在代码编写过程中帮助我们发现错误);
能在代码编译时发现错误,就不要再代码运行时再发现(类型检测就可以很好的帮助我们做到这一点);
能在开发阶段发现错误,就不要在测试期间发现错误;
能在测试期间发现错误,就不要在上线后发现错误;
来看这么一段代码
function foo(message) {
console.log(message.length);
}
foo("hello");
// 后面有其它代码
运行,结果是 5
这么看来这段代码基本是没有什么问题的;
但是存在一个非常大的隐患:当执行**foo()**不传任何参数时,就报错了;
由于没传参数,导致 foo()中的message 是 undefined,undefined 哪来的 length?
这个报错导致后面的代码无法执行,这就导致一行报错,后面所有代码都无法运行,这是你希望看到的吗?;
上面函数并没有对参数进行校验:
- 参数类型
- 是否传参
这时,TypeScript 应运而生。
TypeScript
ts 是拥有类型的js 超集,它可以编译成普通、干净、完整的 js 代码。
js 所有的特性,ts 都支持,并且它紧随 ECMAScript 的标准,所以 es6、es7、es8 等新语法标准,ts 都是支持的;
在语言层面上,不仅仅增加了类型约束,而且包括一些语法的拓展,比如枚举类型(Enum)、元组类型(Tuple)等;
所以,可以将 ts 理解为加强版的 js;
从开发者长远的角度看来,学习 ts 有助于培养类型思维,这种思维对于完成大型项目尤为重要。
TypeScript 官网:https://www.typescriptlang.org/
编译环境
我们知道 ts 是需要转换成 js 的,那谁来负责转换呢?
- tsc,TypeScript Compiler
- babel
全局安装
npm install typescript -g
tsc --version
查看版本
体验
来编写一段 ts 代码
function foo(message: string) {
console.log(message.length);
}
foo("hello");
当你执行 foo()不传参数或者传入非 string 类型的参数,编辑器就会提醒你了,不需要等到运行期间才报错;
然后执行 tsc ts文件
命令,转化为 js 文件,这时会出现同名的 js 文件;
转化后的代码
function foo(message) {
console.log(message.length);
}
foo("hello");
搭建 ts 编译环境
当然,真实开发不是写一个 ts 文件转换一个
我们需要:
- 编写完 ts,它自动转换成 js;
- 然后自动在浏览器上运行;
- 也可以自动更新内容;
搭建方式有几种:
- 通过webpack搭建;
- 安装 node 的一个库ts-node;
使用 ts-node 库搭建
ts-node 做了什么事情?
将 ts 转换成 js,然后在 node 环境上运行
先全局安装 npm install ts-node -g
;
而 ts-node 又依赖于两个库,tslib、@types/node,全局安装它们 npm install tslib @types/node -g
测试
编写这么一段 ts 代码
const name: string = "abc";
const age: number = 18;
console.log(name);
console.log(age);
export {};
为什么要写 export {}
?
因为 ts 文件默认使用全局作用域(所有的 ts 文件),使用 export 语法变成模块,就有独立的作用域了,防止命名冲突
执行 ts-node ts文件
命令,你会看到编辑器的终端打印 abc 和 18
使用 webpack 搭建
本地安装ts-loader和typescript,因为 ts-loader 本身又依赖于 typescript
npm install ts-loader typescript -d
配置 webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.ts$/,
loader: ts - loader,
},
],
},
};
同时还需要tscconfig.js这个属于 ts 的配置文件,可以使用 tsc --init
生成;
最后还需要搭建一个本地服务,利用 webpack-dev-server;
本地安装
npm install webpack-dev-server -d
变量声明
声明的类型可以称之为类型注解;
let/const 标识符: 类型 = 值
例子
let msg: string = "hhh";
小写和大写区别
类型的小写:TypeScript 中的类型;
类型的大写:JavaScript 中的类型对应的包装类;
类型推断
默认情况下进行赋值时,会将赋值的类型,作为标识符的类型
例子
let msg = "hhh";
msg 默认的类型就是字符串类型
数据类型
- number 类型
- boolean 类型
- 字符串类型
- Array 类型
- object 类型
- null 和 undefined
- Symbol 类型
- any 类型
- unknown 类型
- void 类型
- never 类型
- tuple 类型
Array 类型
规定一个数组类型并且元素是 string 类型的例子
写法一,不推荐,可能会和 jsx 冲突
const names: Array<string> = [];
写法二,推荐
const names: string[] = []
any 类型
类型不限制
tuple 类型
区别于数组类型,数组的元素类型一般一致,只有**“共性”**;
而元组可以保留元素的**“个性”**;
元组通常可以作为返回的值,在使用时会非常方便;
const zsf: [string, number, number] = ["hhh", 18, 100];
联合类型
扩大类型的范围;
ts 的类型系统允许使用多种运算符,从现有的类型中构建新类型;
联合类型中每个类型被称之为联合成员(union’s members);
function printID(id: number | string) {
console.log(id);
}
联合类型和可选类型有点类似;
function printID(id?: number) {
console.log(id);
}
可以转换成
function printID(id: number | undefined) {
console.log(id);
}
结合字面量类型
其实字符串也是当成类型,也就是字面量类型;
而字面量类型的值只能和类型一致;
const msg: "hhh" = "hhh";
这时字面量类型就可以和联合类型结合使用了,不和结合类型结合使用,字面量类型没什么意义
let align: "left" | "right" | "center";
align = "right";
类型别名
当联合类型有很多联合成员时,类型会非常长,可读性可能不好;
此时可以给类型起别名,使用关键字type定义;
type IdType = number | string;
type PointType = {
x: number;
y: number;
z?: number;
};
function printID(id: IdType) {
console.log(id);
}
function printPoint(point: PointType) {
console.log(point.x, point.y, point.z);
}