> 本文不讲如何安装,只讲代码中的实际应用
# 一、什么是 TypeScript?
typescript是js的超集,它在js的基础上增加了静态类型校验,可以在运行前校验js中的一些错误并修正。
在定义类型之后,js中任何地方都会有文档提示,对象中包含的值都可以提示出来,这一点让js变得相当友好。
那么想要在已有项目中增加ts需要怎么做?
ts支持渐进式迁移,可配置只检查部分文件,在已有项目中慢慢改造。ts的类型检查不会影响js代码的执行、这意味着,即便类型校验有错误,代码依旧运行良好。
ts的困难在于它需要定义所有的值类型,这个工作量还是蛮大的。
# 二、ts的简单使用
**ts的类型定义语法如下**
- 基础类型:
```javascript
let isDone: Boolean = false;
let str: String = '';
let count: Number = 1;
// 使用联合操作符
let some1: Number | String = 1;
let some2: Number | String = '1';
```
- 数组
```javascript
let arr1: number[] = [1,2];
let arr2: Array
let arr3: [string,boolean] = ['1',false]; // 元组-定义已知数量和类型
```
- 对象(当存在复杂对象时,使用接口和类来声明,后面会讲)
```javascript
let obj: {a: string, b: number } = {a: '我是字符串',b: 2};
```
- any
```javascript
let something: any = 'asd';
```
any用来表示任何类型,ts不会对它进行校验。
> 如果你的ts代码中到处都是any,建议不要使用ts更方便些。
- viod、null、undefined、never
这些值基本没什么用,有兴趣可以自己查看[文档](https://www.tslang.cn/docs/handbook/basic-types.html)
- 枚举 **enum**
**enum**类型是对JavaScript标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字。
```javascript
enum Color {Red, Green, Blue} // 默认情况下,从0开始为元素编号。
let c: Color = Color.Green; // => 1
//你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1开始编号:
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green; // => 2
```
它不但可以使用key获取value,还可以使用value获取key。
```javascript
enum Color {Red=1, Green, Blue}
let colorName: string = Color[2]; // => 'Green'
```
# 三、ts进阶使用
## 类型断言
当你确定某个值的类型时,你可以指定它的类型。它有两种写法:
尖括号写法
```javascript
let someValue: any = "this is a string"; // any未知类型
let str: string = someValue; // error someValue不是string类型
// 断言为string,校验成功
let str: string =
```
as写法
```javascript
let someValue: any = "this is a string";
let str: string = someValue as string
```
## 接口interface
interface用来定义复杂类型(对象、函数、索引类型等)
```javascript
interface Config {
readonly color: string; // 定义只读
width?: number; // 定义可选属性
}
function doSome( option: Config ){
// option.color
// option.width
}
```
同一作用域中同名的interface会自动合并
```javascript
interface Config {
color: string;
width: number;
}
// 同一作用域中
interface Config {
height: number;
}
// 会合并为
interface Config {
color: string;
width: number;
height: number;
}
```
extentds (interface可以使用extentds进行拓展)
```javascript
interface Parent{
readonly color: string; // 可定义常量
width: number;
}
interface Children extends Parent{
height: number;
}
```
## 类
公共,私有 与 存取
1、public
```javascript
class Animal {
name: string; // 默认为public
public id: string; // 也可以标明public
}
```
2、private
```javascript
class Animal {
// private 禁止在类的外部访问
private move() {
// dosomething
}
}
new Animal().move; // 错误: 'move' 是私有的.
```
3、get、set
TypeScript支持通过getters/setters来截取对对象成员的访问。与vue的watcher同理。
```javascript
class Animal {
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
// dosomething
}
}
```
4、readonly标明只读
```javascript
class Animal {
readonly number: number = 8;
}
```
还有static、protected等,这里不过多说明,详情请看[文档。](https://www.tslang.cn/docs/handbook/classes.html)
## 函数
函数类型包含两部分:参数类型和返回值类型。
```javascript
// :number 表示返回值为number
function add(x: number, y: number): number {
return x + y;
}
let myAdd = function(x: number, y: number): number { return x + y; };
```
声明一个未赋值函数
```javascript
let fn: (x: number, y: number) => number;
fn = myAdd;
```
除此之外,interface同样可以声明函数类型
```javascript
// : boolean表示返回值为布尔值
interface Func {
(source: string, subString: string): boolean;
}
// 命名为x,y或者其他都可以
let ff: Func = (x: string, y: string): boolean => {
return x === y
}
```
函数参数类型只会校验它的类型,不会校验它的名字
## type类型别名
类型别名会给一个类型起个新名字。它可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。它的语法看起来像是普通的js。
```java
// 给String重新命名
type Easing = String
// 定义联合类型
type Easing = 'a' | 'b' | 'c'
```
type可以将多个interface联合或者交叉
```java
interface A{
kind: "square";
size: number;
}
interface B{
kind: "rectangle";
width: number;
height: number;
}
interface C{
kind: "circle";
radius: number;
}
type Shape1 = A | B | C; // 联合
type Shape2 = A & B & C; // 交叉
```
type也可以声明函数和元组
```java
// 函数
type Easing = () => string
// 元组
type DudeType = {
[key in Keys]: string // keys是一个索引类型
}
```
> type和interface功能类似,但type更像一个值而不是一个类型。在两者都能实现需求的情况下,官方建议优先使用interface。
# 四、ts高级用法--泛型
考虑到代码的可重用性和拓展性,ts允许使用泛型来定义未知类型,使用尖括号语法。
```javascript
// 当入参未知时,我们可定义一个泛型
function identity
return arg;
}
// 它可以这样用,表示数组
function identity
return arg;
}
// 或者表示对象
function identity
return arg.x;
}
```
泛型支持extends语法
```javascript
interface Lengthwise {
length: number;
}
function loggingIdentity
console.log(arg.length); // 可以用时length属性
return arg;
}
```
泛型promise使用示例
```typescript
// Promise
// catch类型默认是any
let ajax =
return new Promise((resolve) => {
axios.get('/list').then(res=> {
resolve(params)
})
})
}
// 使用时
ajax<{a: string,b:number}>(params).then(res=>{
// res 类型为{a: string,b:number}
)
```
>此处只讲了typescript的一些常见用法和问题,更多说明请看官方文档。[(中文文档3.1](https://www.tslang.cn/docs/release-notes/typescript-3.1.html),[英文文档4.1)](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html)
==一些运算操作符==
1. !断言此处有值。
```javascript
let y!:number = 1; // 表示y必定有值
```
2. ?表示可能未定义。
```javascript
let obj = {
y?: number, // 相当于 number | undefined
z: string
}
let num: number;
num = obj.y; // error,不能将类型“number | undefined”分配给类型“number”。
```
3. ?? 空值合并。
通常我们取一个可能存在的值时,会像这样
```javascript
let obj = {
y?: number
}
let num: number;
num = obj.y || 1;
```
但当obj.y为0时,它会存在问题。所以ts提供了更好的解决方案。??只会判断null和undefined两个值。
```javascript
let obj = {
y?: number
}
let num: number;
num = obj.y ?? 1; // 即使y为0,也会得到0,而不是1
```
4.!取值用法和?的赋值用法。
!表示必定有值,?表示可能有值,所以他们也可以这样使用
当你确定值必定存在时
```javascript
let obj: {
a?: {
b?: number
}
} = { a: { b: 1 } };
let x: number = obj.a.b; // 报错,对象可能未定义
let y: number = obj!.a!.b; // 通过
```
当你不确定值是否存在
```javascript
let obj: {
a?: {
b?: number
}
}
obj.a.b = 1; // 报错
obj?.a?.b = 1; // 通过
```
5. !(放在value之后)允许null和undefined
```javascript
let y:number
y = null // 无法通过编译
y = undefined // 无法通过编译
y = null! // 通过
y = undefined! // 通过
```
6. 最新特性??=、||=、&&=
有时候我们需要对可能存在的值给一个默认值
```javascript
let obj = {
y?: number
}
// 正常情况
obj.y = obj.y ? obj.y : 1;
// 使用??空值合并
obj.y = obj.y ?? 1;
// 使用??=运算符,他看起来有点像 +=和-=
obj.y ??= 1;
```