TS基础语法
1 | const a:string = 'hi' |
1 | // 函数的类型声明 |
联合类型
- 联合类型:由两种或多种其他类型组成的类型,表示可能是这些类型中的任何一种的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17type A = {
name: 'a';
age: number
}
type B = {
name: 'b',
gender: string
}
// 联合A与B两种类型
// 使用要点:A、B两个类型中必须至少有一个相同的key,然后才能根据这个key的值做区分
const f = (n: A|B) => {
if(n.name === 'a'){ // 类型A与类型B中有相同的key,即name
n.age
} else {
n.gender
}
}
TS vs. JS
- 语法层面:TypeScript = JavaScript + Type(TS是JS的超集)
- 执行环境:浏览器、nodejs可以直接执行JS,但不能执行TS(Deno可以执行TS)
- 编译层面:TS有编译阶段,JS没有编译阶段(只有转译和ESlint阶段)
- 编写层面:TS更难写一些,但类型更安全
- 文档层面:TS代码写出来就是文档,IDE可以完美提示。JS提示主要靠TS
将TS转译为JS的方法
- webpack + babel
- Vite 2
- tsc 即 typescript compiler
使用TS的好处
- 检查bug:增加类型检查,可以在写代码(编译时)就报错,不需要等到代码运行时
- 智能提示:要求你做好类型判断(收窄类型),写代码更安全
1
2
3
4
5
6
7
8
9
10import React from 'react'
import ReactDOM from 'react-dom'
const root = document.getElementById('root')
// 这里root可能的类型为 HTMLElement || null
if(root !== null) { // 判断 root不为null 才执行
ReactDOM.render(<div>hi</div>, root)
} else {
report('root为空')
}
any vs. unknown
两者都是顶级类型(top type),任何类型的值都可以赋值给顶级类型变量
1
2let foo:any = 123; // 不报错
let bar:unknown = 123; // 不报错但 unknown 比 any 的类型检查更严格,any什么检查都不做,unknown要求在使用前先明确类型(类型收窄)
1
2const value:unknown = "Hello World";
const someString:string = value; //报错:Type 'unknown' is not assignable to type 'string'
1 | const value: unknown = "Hello World"; |
- 若改为any,基本在哪都不报错。所以优先用unknown,类型更安全
never
- never是底类型,表示不应该出现的类型(什么都不是,出现never表示代码有问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24interface A {
type: 'a'
}
interface B {
type: 'b'
}
type All = A | B
function handleValue(val: All) {
switch (val.type) {
case 'a':
// 这里 val 被收窄为 A
break
case 'b':
// val 在这里是 B
break
default:
// val 在这里是 never
const exhaustiveCheck: never = val
break
}
}
type 和 interface 的区别?
组合方式:interface 使用 extends 来实现继承,type 使用 & 来实现联合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// interface的继承方式
interface B {
b: string
}
interface A extends B {
a: string
}
const a:A = {
a: 'hi',
b: 'hi'
}
// type的继承方式
type BB = {
bb: string
}
type AA = {
aa: string
} & BB
const aa:AA = {
aa: 'hi',
bb: 'hi'
}扩展方式:interface 可以重复声明用来扩展,type 一个类型只能声明一次
1
2
3
4
5
6
7
8
9
10
11interface A {
a:string
}
// interface可以重复声明,且两次声明会自动合并
interface A {
b:string
}
const a:A {
a: 'hi',
b: 'hi'
}
1 | type A = { |
- 范围不同:type 适用于基本类型,interface 一般不行
- 命名方式:interface 会创建新的类型名,type 只是创建类型别名,并没有新创建类型
1
2
3type X = number // 给number取了一个别名为 X
const x:X = 1
type Y = typeof x // Y === number
TS工具类型的作用和实现
Partial(部分类型)
1
2
3
4
5
6
7
8
9// 创建一个用户,但用户id需要上传服务器后才能拿到
interface User {
id: string;
name: string;
}
const user: Partial<User> = {
name: 'joyce' // 创建用户时可以先不传id
}Required(必填类型)
1
2
3
4
5
6
7
8
9interface User {
id: string;
name: string;
}
const user: Required<User> = { // id和name都必填
id: '111',
name: 'joyce'
}Readonly(只读类型)
1
2
3
4
5
6
7
8
9
10
11interface User {
id: string;
name: string;
}
const user: Readonly<User> = {
id: '111',
name: 'joyce'
}
user.id='222' // 报错,user是只读的,不可更改Exclude(排除类型)&& Extract(提取类型) => 后接基本类型
1
2
3
4type Dir = '东' | '南' | '西' | '北'
type Dir2 = Exclude<Dir, '北'> // 排除 '北'
type Dir3 = Extract<Dir, '东'|'西'> // 只要 '东' '西'Omit(排除key类型)&& Pick(提取key类型) => 后接对象类型
1
2
3
4
5
6
7
8interface User {
id: string;
name: string;
age: number;
}
type God1 = Omit<User, 'age' | 'id'> // 排除age和id,God此时只有name属性
type God2 = Pick<User, 'name'> // God2只要name属性ReturnType(返回值类型)
1
2
3
4
5
6// 获取函数返回值类型
function f(a:number, b:number){
return a+b
}
type A = ReturnType<typeof f>
TS泛型
1 | type Add<T> = (a:T, b:T) => T |
用泛型封装网络请求
1 | type T = Partial<Omit<User, 'id'>> |