1 JS与TS的数据类型

  • JS(8种)

    • number boolean string bigint symbol
    • null undefined
    • object (含Array Function Date..)
  • TS

    • JS 8种
    • void never enum unknown any
    • 自定义类型interface type(type严格来讲算类型别名)

2 理解TS的数据类型

  • 集合的角度理解TS数据类型
  • 即每一个type都表示类型的集合
  • &表示交集|表示并集
1
2
3
4
type number = 1 | 1.1 | 1.11 | ... | 2 | ... ;
type string = 'a' | 'ab' | ... ;
type boolean = true | false ;
type Object = {?} | Array | Function | String | Number | Boolean | ... ;

2 描述number、boolean和string的数据类型

  • 先说结论:使用小写的
  • 2 vs new Number(2)
1
2
3
4
5
6
7
8
9
var a = 2
// 内存中会以二进制的形式开辟值为2的空间
var b = new Number(2)
// {
//	constructor:...
//	toFixed:...
//	toString:...
//	valueOf: () => 2
// }
  • 为什么一个值身上会存在toFixed方法?
1
2
const a = 10
a.toFixed(2) //为什么一个值身上会存在toFixed方法?
  • 说明JS包装了这个a,使其具有了Number实例对象的属性与方法
  • 正是由于包装对象机制的存在,给人一种“JS一切皆对象”的假象
  • JS中的Number、String和Boolean只用于包装对象,不适合作为数据类型

3 描述普通对象的数据类型

使用Objectobject去描述对象的数据类型,太过于宽泛,类似any

所以一般使用索引签名Record泛型来描述普通对象

1
2
3
4
5
// 表示对象的key为string,value为number
// 索引签名(k为任意小写字符)
type A = { [k: string]: number }
// Record泛型
type A = Record<string, number>

4 描述数组对象的数据类型

使用Array去描述数组的数据类型,太过于宽泛,一般使用

Array<?>

string[]

[string, number]

1
2
3
const a:Array<number> = [1, 2, 3]
const b:string[] = ['a', 'b']
const c:[1, 2] = [1, 2]

5 描述函数对象的数据类型

使用Function去描述数组的数据类型依然不够精确,一般使用箭头函数(?) => ?

1
2
type Func = (a:number) => number
const func:Func = (a) => a + 1
1
2
3
4
5
6
7
type FuncWithThis = (this: Person, name: string) => void
type Person = { name: string, func:FuncWithThis }
const func:FuncWithThis = function(hello){
	console.log(hello, this.name)	
}
const p:Person = {name: 'gsq', func}
p.func('hello')

6 其他对象

直接用class描述,例如

1
2
3
4
5
const d:Date = new Date()
const r:RegExp = /a+b/
const m:Map<string, number> = new Map()
const wm:WeakMap<{name:string}, number> = new WeakMap() // WeakMap的key必须是对象
const s:Set<number> = new Set()

7 any、unknown和never

  • any是全部类型的全集

  • unknown表示暂时不能确定类型,注意在使用时断言即可

1
2
const a:unknown = axios.get(...)
(a as number).toFixed(2)
  • never是空集合,表示不应该出现的类型,出现说明出错了
1
2
3
4
5
6
7
8
9
type A = string & number // never
// 在类型判断中检查类型用
type A = string | number
let a:A
if(typeof a ==='string'){}
else if(typeof a === 'number'){}
else {
// 此时a为never,表示此处不应该对a进行操作
}

8 enum类型

  • 使用enum的两种情况

    • status状态字段
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    // 定义
    enum S {
    	todo = 0,
    	done,
    	deleted
    }
    let status = 0 
    // 使用
    status = S.todo
    status = S.done
    
    • 前端权限控制(二进制与计算)
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    enum Permission {
    	None = 0,		//0000
    	Read = 1 << 0,	//0001
    	Write = 1 << 1,	//0010
    	Delete = 1 << 2,//0100
    	Manage = Read | Write | Delete // 0111
    }
    const user = {
    	permission: 0b0101
    }
    // 与计算 只有1&1才为1
    // a&b===b 说明a有b的所有1
    if((user.permission & Permission.Write) === Permission.Write) {
    	console.log('有写权限')
    }
    
  • 不使用enum的情况

    • 当枚举为string时,应使用type
    1
    
    type S = 'done' | 'working' | 'stop'
    
    • 以上两种情况之外的,都不建议使用enum

9 type和interface

9.1 type

  • 类型别名(Type Aliases)
  • 其他类型取个外号,并不会产生新的类型
1
2
type Name = string
type FalseLike = false | 0 | null | undefined | ''

9.2 interface

  • 声明接口
  • 描述对象的属性
1
2
3
4
5
interface Data { [k: string]: string }
interface Point { x: number; y: number }
interface Points extends Array<Point> {}
interface Fn { (x: number, y: number): number }
interface Data2 extends Date {}
  • interface就是把type能做的事用面向对象的思想翻译了一下(非绝对)

9.3 区别

  1. interface只描述对象的属性;type则描述所有数据类型

  2. type只是别名;interface则是类型声明

  3. type不可重新赋值,不方便扩展;interface具有自动合并的特性,方便扩展

    • 对外API尽量用interface,对内尽量用type
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 自动合并,不会覆盖
interface X { name: string }
interface X { age: number }
const x:X = { name: 'gsq', age: 20 }
// 扩展已经存在的interface custom.d.ts
import { AxiosRequestConfig } from 'axios'
declare module 'axios' {
    export interface AxiosRequestConfig {
        _mock?: string
    }
}
// 扩展全局的String
declare global {
    interface String {
        padZero(length: number): string
    }
}