TypeScript中的类型

93 阅读4分钟

1 基本类型

1.1 理解TS的数据类型

从集合的角度去理解TS的数据类型会容易理解一些。比如,数字类型(number)就是有1、1.1、1.11···、2、2.1、2.11··· 所有的数字组成的集合。字符串同理。

1.2 数据类型分类

1.2.1 JS datatype

number、string、Boolean、undefined、null、bigint、symbol、object(含Array、Function、Date···)

1.2.2 TS datatype

以上所有、void、never、enum、unknown、any、自定义类型type、interface

1.3 表示方式

  • number
type A = number
const a: A = 1
  • string
type A = string
const a: A = 'name'
  • boolean
type A = boolean
const a: A = true(false)
  • undefined
type A = undefined
const a: A = undefined
  • null
type A = null
const a: A = null
  • bigint
const n: bigint = 100n
console.log(n)
  • symbol
const s: symbol = Symbol('s')
console.log(s)
  • object

由于object太不精确,所以TS开发者一般使用<索引签名>或<Record泛型>来描述普通对象

  1. 索引签名
type Person = {
  name: string,
  age: number
}
  1. Record泛型
type A2 = Record<string, number>
  1. 普通方式
type A3 = {
  // 键值可以不是字符串,但不能是undefined
  [k: number]: string
  
  // symbol 类型
  [k1: symbol]: number
}
const a: A3 = {
  name: 1,
  123: 6, // 对象的默认操作会将键自动转化为字符串
}

const s = Symbol()
const a: A = {
  [s]: 6,
}
  • 用[]和Array泛型描述数组
// 方式一:泛型
const arr: Array<number> = [1, 2]

// 方式二:字面量
const arr1: string[] = ['hi', 'i']

// 方式三:单独表示变量类型
type A3 = [string, number]

// 二元组
type Two = [number, number]

// 三元组
type Three = [number, number, number]

// type number = 1 | 2 | 3 | 1.1.1 | ...
// 这种写法只不过将每个值进行了收缩
type A = [1, 2, 3]
const a: A = [1, 2, 3]
  • 描述函数对象
type FnA = (a: number, b: number) => number
// ts 是松散的函数类型检查,即函数没有传形参不会报错
// 类型推导
const a: FnA = (x, y) => {
  return 1
}

type FnReturnVoid = () => void
type FnReturnUndefined = () => undefined

const f1: FnReturnVoid = () => {
  console.log('hi')
}
const f2: FnReturnUndefined = () => {
  console.log('hi')
  return undefined
}

type Person = {
  name: string
  age: number
  sayHi: FnWithThis
}
type FnWithThis = (this: Person, name: string) => void

// 一般情况下使用this不能使用箭头函数
const sayHi: FnWithThis = function () {
  console.log('hi' + this.name)
}

const x: Person = {
  name: 'lwz',
  age: 18,
  sayHi,
}
x.sayHi('Jack')
sayHi.call(x, 'Jack')
  • 描述其他对象
// 其他对象一般直接用class描述
const d: Date = new Date()
const r: RegExp = /ab+c/
const r2: RegExp = new RegExp('ab+c')
const m: Map<string, number> = new Map()
m.set('xxx', 1)
const wm: WeakMap<{ name: string }, number> = new WeakMap()

const s: Set<number> = new Set()
s.add(123)
const s1: Set<{ name: string }> = new Set()
s1.add({ name: 'lwz' })
const ws: WeakSet<string[]> = new WeakSet()
  • any 和 unknown
// any 包含任何类型
// unknown 一般用于请求外界的数据时不知道类型,请求完数据之后使用断言将其类型固定
const a: unknown = 1
const b = a as number // 断言
console.log(a)
  • never
// any 是全集,unknown是未知集,never是空集

type A = string | number | boolean

const a: A = 'hello' as any
if (typeof a === 'string') {
  a.split('')
} else if (typeof a === 'number') {
  a.toFixed(2)
} else if (typeof a === 'boolean') {
  a.valueOf()
} else {
  console.log('没了')
}
  • 何时使用enum
// enum A {
//   todo = 0,
//   done,
//   archived,
//   deleted,
// }

// let Estatus: A = A.done
// console.log(Estatus)

enum Permission {
  None = 0,
  Read = 1 << 0, // 0001
  Write = 1 << 1, // 0010
  Delete = 1 << 2, // 0100
  Managa = Read | Write | Delete, // 0111
}
type User = {
  permission: Permission
}
const user1: User = { permission: 0b0101 }
// if ((user1.permission & Permission.Write) === Permission.Write) {
//   console.log('有权限')
// }
// if ((user1.permission & Permission.Managa) === Permission.Managa) {
//   console.log('有管理权限')
// }
if (canWrite(user1.permission)) {
  console.log('拥有写权限')
}
if (canManaga(user1.permission)) {
  console.log('拥有管理权限')
}

function canWrite(p: Permission) {
  return (p & Permission.Write) === Permission.Write
}

function canManaga(p: Permission) {
  return (p & Permission.Managa) === Permission.Managa
}
  • 何时不用enum
// enum Fruit {
//   apple = 'apple',
//   banana = 'banana',
//   pineapple = 'pineapple',
//   watermelon = 'watermelon',
// }

// let f: Fruit = Fruit.apple

// f = Fruit.watermelon

type Fruit = 'apple' | 'banana' | 'pineapple' | 'watermelon'

let f: Fruit = 'banana'
f = 'pineapple'
console.log(f)

/**
 * enum number √
 * enum string ×
 * enum other ×
 */
  • type和interface两个区别
// 类型别名 alias

type Name = string

// type 里面只能是类型不能是值,而NaN就是一个值
// 0就是一个类型,表示的是一个集合里面只有一个值0
type FalseLike = 0 | '' | null | undefined | false

const a: Name = 'lwz'

// 带有属性的函数声明
type FnWithProp = {
  // 类型里面用的冒号, 非类型声明用的是箭头函数
  // (a: number, b: number) => number
  (a: number, b: number): number
  prop: string
}

const f: FnWithProp = (x, y) => {
  return x + y
}
f.prop = 'hello'
console.log(f)

// type 只是一个别名,并不是真正的声明一个类型
type A = string
type B = A

const x: A = 'hello'
const y: B = x
console.log(x, y)

// interface 接口 --> 面向对象 Oriented Object Program

interface A1 {
  a: number
  b: string
  // 索引签名
  // [k: string]: number
}

type A2 = Array<string> & {
  name: string
} & X

interface X {
  age: number
}

interface A3 extends Array<string>, X {
  name: string
}

interface Fn {
  (a: number, b: number): number
  xxx: number
}
const f1: Fn = (x, y) => {
  return x + y
}
f1.xxx = 100
console.log(f1)

// interface D extends Date {
//   // 下面这行代码会报错
//   // xxx: number
// }
// const d: D = new Date()
// // d.xxx = 100
// console.log(d)

interface D extends RegExp {
  // 也会报错
  // xxx : number
}
// const d: D = new RegExp(/ab+c/)
// // d.xxx = 100
// console.log(d)

/**
 * 总结type和interface的区别
 * 1.
 * type 描述所有的数据
 * interface 描述对象的属性 注意: 仅限对象
 * 2.
 * type 给其他类型取个名字,只是一个别名
 * interface 则是类型声明
 */

// type 只是一个别名, 所以下面的BB类型就相当于跳过了AA,直捣黄龙
type AA = string
type BB = AA

// interface 定义的是以真名, 所以下面D是实实在在存在的
interface D extends Date { }
type E = D

// 简化代码的作用
type Id = string | number

const user: Id = 'xxxx'
const customer: Id = 'xxxx'

export { }

  • type和interface的第三个区别
// type 不可赋值,一旦定义好类型之后,后面就不可以再修改
// 而 interface 还有修改的可能
// 举例: axios 在发送请求的时候,第一个参数是url,而第二个参数是一个配置对象,如果此时使用 type 无法定义,因为不知道后端的请求参数是什么, 此时使用 interface 就是好很多

// interface 可以自动扩展
interface X {
  name: string
}

interface X {
  age: number
}

const a: X = {
  name: 'lwz',
  age: 18,
}

/**
 * 区别三:
 * 对外API 尽量使用 interf
 * 方便扩展
 * 对内API 尽量使用 type
 * 防止代码分散
 */

  • void
type Fn = () => void
const f: Fn = () => {
  // return undefined
  // return 1
  return 'hi'
}

// 虽然上面的几种方式不会报错,但是在编译的时候会报错
// const a = f()
// console.log(a.toFixed())

// 但是下面这种方式不会报错
function Fn(): void {
  // return 1
}
  • 俩number、俩string、俩boolean

image.png 我们在创建了一个number类型的特定值后,其实就是做了以下操作:

image.png 因此:

image.png