1. TS介绍

1.1 TS是什么

TypeScript 是 JS的超集

TypeScript = Type + JavaScript

1
2
3
4
//有明确类型
let age1: number = 18
//无明确类型
let age2 = 18

1.2 TS为什么要添加类型支持

  • 背景:JS的类型系统存在“先天缺陷”,JS代码中绝大部分错误都是类型错误(Uncaught TypeError)。

  • 问题:增加了找Bug、改Bug的时间,严重影响开发效率。

从编程语言的动静来区分,TypeScript属于静态类型的编程语言,JS属于动态类型的编程语言。

静态类型:编译期做类型检查;

动态类型:执行期做类型检查。 代码编译和代码执行的顺序:1编译2执行。

对于JS来说:需要等到代码真正去执行的时候才能发现错误(晚)。
对于TS来说:在代码编译的时候(代码执行前)就可以发现错误(早)。
并且,配合VSCode等开发工具,TS可以提前到在编写代码的同时就发现代码中的错误,减少找Bug、改Bug时间。

2. TS常用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//原始类型
let age: number = 19
let myname: string = 'zll'
let flag: boolean = true
let a: null = null
let b: undefined = undefined
let s: symbol = Symbol()

//对象类型
// 在TS中更加细化,每个具体的对象都有自己的类型语法

//数组
let numbers: number[] = [1, 3, 5]
let str_list: Array<string> = ['a', 'b', 'c']
//数组中既有number 又有 string
// | 叫做联合类型 由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种
let list: (number | string)[] = [1, 'a', 2]
//没有括号就是可以为number 或者为 string[]
let list1: number | string[] = ['a', 'b', 'c']
let list2: number | string[] = 123

//函数类型
//函数类型指的是函数参数和返回值的类型
// 单独指定
function add(a: number, b: number): number{
return a + b
}
const add = (a: number, b: number): number => {
return a + b
}
//同时指定 只适用于函数表达式
const add: (a: number, b: number): number = (a, b) => { return a + b}
//没有返回值为void
const print = (msg: string): void => {
console.log(msg)
}
//可选参数
//在可选参数后添加问好 ?
//可选参数只能出现在参数列表最后,可选参数后不能出现必选参数
function add(a?: number, b?: number): number {
return a + b
}

//对象类型 JS中的对象是由属性和方法构成的,而TS中对象的类型就是在描述对象的结构(有什么类型的属性和方法)
let person: {name: strinh; age: number; say(): void} = {
name: 'zll',
age: 25,
say(){
console.log('hello')
}
}
//可以通过换行去掉;
let person: {
name: string
age: number
say(): void
} = {
name: 'zll',
age: 25,
say(){
console.log('hello')
}
}
//存在可选属性,语法与可选参数一致

//接口
//当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。
interface IPerson {
name: string
age: number
say(): void
}
let person: IPerson = {
name: 'zll',
age: 25,
say(){
console.log('hello')
}
}
//接口的继承
interface IStudent extends IPerson{
course: string[]
}

//元组 另一种类型的数组,他确切知道包含了多少个变量和变量类型
let position: [number, number] = [1, 2]

//字面量类型 不管是字符串还是数值都可以作为类型
let str1 = 'hello' //类型为string

const str2 = 'hello' // 类型为‘hello’
//可以用来配合联合类型一起使用,用来表明一组明确的可选值列表
function changeDirection(direction: 'up' | 'down' | 'left' | 'right'): void{

}

//枚举类型 类似字面量价联合类型 通过点访问枚举成员
enum Direction { Up, Down, Left, Right }

function changeDirection(dirention: Direction){}

changeDirection(Direction.Up)


2.1 JS 已有类型

  • 原始类型
    • number
    • string
    • boolean
    • null
    • undefined
    • symbol
  • 对象类型
    • 数组
    • 对象
    • 函数

2.2 TS 新增类型

  • 联合类型

    用 | 分割类型

  • 类型别名

  • 接口

    与类型别名的区别

    相同点: 都可以为对象指定类型

    不同点:

    • 接口只能为对象指定类型
    • 类型别名可以为任意类型指定别名
    • 接口可以继承
  • 元组

  • 字面量类型

  • 枚举

    枚举成员是有值的,默认从0开始自增长

    也可以给枚举成员初始化值

    数字枚举 枚举值都为数字

    字符串枚举没有自增长行为,需要每个都赋值

    其他类型在编译成js后会自动去掉

    枚举因为有值会被编译成js

  • void

  • any

    不推荐使用,会失去TS类型保护的优势,对象为any类型时,可以对该值进行任意操作,并且不会有报错

2.3 类型别名

1
2
3
4
//为任意类型起别名 简化类型的写法
type CustomArray = (number | string)[]
let list1: CustomArray = [1, 2, 'a']

  • 使用type关键字
  • 类型别名可以为任意合法的变量名

2.4 类型推论

在TS中,某些没有明确指出类型的地方,TS的类型推论机制会帮助提供类型。
换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写!
发生类型推论的2种常见场景:

  1. 声明变量并初始化时

  2. 决定函数返回值时。

2.5 类型断言

有时候你会比TS更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。

类型推论可能会返回一个比较宽泛的类型,我们不能使用这个宽泛的类型来访问一些特有的属性和方法

  1. 使用as关键字实现

  2. as后跟一个更加具体的类型

  3. 也可以通过<> 实现

  4. 在控制台用console.dir()打印DOM元素,在属性列表的最后可以看到元素的类型

1
2
3
const aLink = document.getElementById('link') as HTMLAnchorElement

const aLink = <HTMLAnchorElement>document.getElementById('link')

2.6 typeof

只能查询变量或者对象属性的类型

1
2
3
4
5
typeof "hello" // string

let p = {x: 1, y: 2}
function f(point: {x: number; y: number})()
function f(point: typeof p){}

3. TS中的高级类型

3.1 概述

  • class类
  • 类型兼容性
  • 交叉类型
  • 泛型和keyof
  • 索引签名类型和索引查询类型
  • 映射类型

3.2 class

  1. 根据TS中的类型推论,可以知道Person类的实例对象p的类型是Person
  2. TS中的class,不仅提供了class的语法功能,也作为一种类型存在。
1
2
3
4
5
6
class Person {
age: number
gender = 'man'
}

const p = new Person()
  • 声明成员age,类型为number(没有初始值)。

  • 声明成员gender,并设置初始值,此时,可省略类型注解(TS类型推论为string类型)。

  • 成员初始化(比如,age:number)后,才可以通过this.age来访问实例成员。

1
2
3
4
5
6
7
8
9
class Person {
age: number
gender: string

constructor(age: number, gender: string){
this.age = age
this.gender = gender
}
}
  • 需要为构造函数指定类型注解,否则会被隐式推断为any;构造函数不需要返回值类型。