ts其实也看了好久了,一直打算把ts在项目中用起来,无奈这段时间一直在看node,docker也忘的差不多了,索性在复习一下ts,顺便输出一些笔记记录一下,毕竟自己吃过的东西在看起来也会快一些…….
TypeScript简介
- TypeScript 是 JavaScript 的一个超集
- 它可以编译成纯 JavaScript。
- 编译出来的 JavaScript 可以运行在任何浏览器上。
- TypeScript 编译工具可以运行在任何服务器和任何系统上。
- TypeScript 是开源的
- TypeScript 中,使用 : 指定变量的类型, : 的前后有没有空格都可以。
优点
- 增加了代码的可读性和可维护性
提供了类型系统和对 ES6 的支持
编译阶段就发现大部分错误
- 兼容性好
TypeScript 是 JavaScript 的超集, .js 文件可以直接重命名为 .ts 即可
即使不显式的定义类型,也能够自动做出类型推论
即使 TypeScript 编译报错,也可以生成 JavaScript 文件
兼容第三方库,即使第三方库不是用 TypeScript 写的,也可以编写单独的类型文件供 TypeScript 读取
缺点
- 概念多
有一定的学习成本,需要理解接口(Interfaces)、泛型(Generics)、类(Classes)、枚举类型(Enums)
短期可能会增加一些开发成本,毕竟要多写一些类型的定义
安装
npm install -g typescript
编译一个 TypeScript 文件很简单:tsc xxx.ts
TypeScript 编写的文件以 .ts 为后缀,用 TypeScript 编写 React时,以 .tsx 为后缀
配置
如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。
- tsconfig.json
1 | { |
基础
1.原始数据类型
- js的数据类型分为两类:原始数据类型 - Primitive data types(布尔值,数值,字符串,null,undefined,以及symbol)和对象类型- Object types
布尔值 在 TypeScript 中,使用
boolean定义布尔值类型 ,而 Boolean 是JavaScript 中的构造函数
使用
number定义数值类型
使用
string定义字符串类型:
在 TypeScript 中,可以使用
null和undefined来定义这两个原始数据类型:
1 | // undefined 类型的变量只能被赋值为 undefined , null 类型的变量只能被赋值为 null |
- 空值
JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void 表示没有任何返回值的函数:
1 | function alertName(): void { |
2. 任意值
- 任意值(Any)用来表示允许赋值为任意类型。
如果是一个普通类型,在赋值过程中改变类型是
不被允许的:但如果是 any 类型,则允许被赋值为任意类型。
在任意值上访问任何属性都是允许的,也允许调用任何方法:
1 | let anyThing: any = 'hello'; |
可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
3. 类型推论 - Type Inference
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是
类型推论。
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查:
1 | let myFavoriteNumber; // 只定义 没赋值 any类型不会进行类型推论 |
4. 联合类型 - Union Types
联合类型(Union Types)表示取值可以为多种类型中的一种,但是不能是其他类型
联合类型使用 | 分隔每个类型。
1 | let myFavoriteNumber: string | number; |
- 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
1 | function getLength(something: string | number): number { |
5. 对象的类型——接口 Interfaces
接口(Interfaces)是对行为的抽象,而具体如何行动需要由类(classes)去实现(implements)
接口一般首字母大写,有的编程语言中会建议接口的名称加上 I 前缀。
定义的变量比接口少了一些属性是不允许的,多一些属性也是不允许的,可见,赋值的时候,变量的形状必须和接口的形状保持一致
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
确定属性
1 | interface Person { |
可选属性
- 有时我们希望不要完全匹配一个形状,那么可以用可选属性:
可选属性的含义是该属性可以不存在,这时仍然不允许添加未定义的属性
1 | interface Person { |
任意属性
- 有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
1 | interface Person { |
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性:
1 | interface Person { |
只读属性
- 有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用readonly 定义只读属性:
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
1 | interface Person { |
6. 数组的类型
- 1)「类型 + 方括号」表示法 let fibonacci: number[] = [1, 1, 2, 3, 5];
数组的项中不允许出现其他的类型
数组的一些方法的参数也会根据数组在定义时约定的类型进行限制
1 | fibonacci: number[] = [1, 1, 2, 3, 5]; |
- 2) 数组泛型(Array Generic) Array
来表示数组
let fibonacci: Array
= [1, 1, 2, 3, 5];
- 3) 用接口表示数组
1 | interface NumberArray { |
- any 在数组中的应用
用 any 表示数组中允许出现任意类型 let list: any[] =[‘xx’,1,true]
- 类数组(Array-like Object)不是数组类型,比如 arguments
事实上常见的类数组都有自己的接口定义,如 IArguments , NodeList ,HTMLCollection 等:
1 | function sum() { |
7. 函数的类型
- 函数声明(Function Declaration)
1 | // 函数声明(Function Declaration) |
- 一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单
1 | function sum(x: number, y: number): number { |
- 函数表达式(Function Expression)
1 | // 函数表达式(Function Expression) |
1 | // 在 TypeScript 的类型定义中, => 用来表示函数的定义 |
可选参数
与接口中的可选属性类似,我们用 ? 表示可选的参数:
可选参数必须接在必需参数后面(可选参数有了默认值就不受「可选参数必须接在必需参数后面」的限制了)
1 | function buildName(firstName: string, lastName?: string) { // lastName表示可选的参数 |
参数默认值
- TypeScript 会将添加了默认值的参数识别为可选参数
1 | function buildName(firstName: string, lastName: string = 'Cat'){ |
剩余参数
…rest 的方式获取函数中的剩余参数
rest 参数只能是最后一个参数
事实上, rest 是一个数组。所以我们可以用数组的类型来定义它:
1 | function restFun(firstArg:number[],...argus:any[]){ |
使用接口定义函数
- 我们也可以使用接口的方式来定义一个函数需要符合的形状:
1 | interface SearchFunc { |
8. 重载 overload
- 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理
1 | function reverse(x: number): number; |
- TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有
包含关系,需要优先把精确的定义写在前面
9. 类型断言 Type Assertion
可以用来手动指定一个值的类型
<类型>值或者值 as 类型
- 在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种
值 as 类型。
1 | function getLength(something: string | number): number { |
此时可以使用类型断言,将 something 断言成 string :
1 | function getLength(something: string | number): number { |
类型断言的用法如上,在需要断言的变量前加上
即可 类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
1 | function toBoolean(something: string | number): boolean { |
10.声明文件
- 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
声明语句
- 我们需要使用 declare var 来定义它的类型
1 | declare var jQuery: (selector: string) => any; // 定义了jQuery是一个包含selector为string的函数,返回值为any |
有了上面的声明语句,ts才能在编译的时候认识第三方导入的jQuery
声明文件
- 通常我们会把声明语句放到一个单独的文件( jQuery.d.ts )中,这就是声明文件
声明文件必需以 .d.ts 为后缀。
1 | // src/jQuery.d.ts |
第三方声明文件
- 更推荐的是使用 @types 统一管理第三方库的声明文件
1 | npm install @types/jquery --save-dev // 以 jQuery举例: |
11. 内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型
内置对象是指根据标准在全局作用域(Global)上存在的对象
用 TypeScript 写 Node.js
- ECMAScript 标准提供的内置对象有:Boolean 、 Error 、 Date 、 RegExp 等
1 | let b: Boolean = new Boolean(1); |
- DOM 和 BOM 提供的内置对象有:Document 、 HTMLElement 、 Event 、 NodeList 等。
1 | let body: HTMLElement = document.body; |
Node.js 不是内置对象的一部分,如果想用 TypeScript 写 Node.js,则需要引入第三方声明文件:npm install @types/node –save-dev