ts学习笔记

415 阅读7分钟

一、类型系统

类型系统有两种,如下:

显式注解类型

告诉编辑器所有值的类型

const a:number = 1 // a是一个数字
const b:string = 'hello' // b是一个字符串

自动推导类型

自动推导值的类型

const a = 1  // a是一个数字
const b = 'hello' // b是一个字符串

一般来说,最好让ts推导类型,少数情况下才显式注解类型

二、并集类型与交集类型

并集类型

并集类型 type1 | type2 ,表示要么满足type1,要么满足type2,要么同时满足type1和type2,否则会波浪线提示

interface objI {
  name: string,
  age: number
}
interface objI2 {
  name: string,
  sex: boolean
}
// 并集类型使用
let obj: (objI | objI2) = {
  name: '正常执行',
  age: 12
}
obj = {
  name: '正常执行',
  sex: true
}
obj = {
  name: '正常执行',
  sex: true,
  age: 12
}
obj = {
  name: '我不能满足objI,也不能满足objI2,所以我也会波浪线提示'
}
obj = {
  name: '正常执行',
  sex: true,
  age: 12,
  asdf: '我是objI和objI2都不存在的属性,所以我会波浪线提示'
}

交集类型

交集类型type1 & type2,表示必须同时满足type1和type2

interface objI {
  name: string,
  age: number
}
interface objI2 {
  name: string,
  sex: boolean
}
let obj: (objI & objI2) = {
  name: '正常执行',
  age: 12,
  sex: true
}
obj = {
  name: '我不能满足typeI, 只满足typeI2,所以会波浪线提示',
  sex: true
}
obj = {
  name: '我不能满足objI,也不能满足objI2,所以我也会波浪线提示'
}
obj = {
  name: 'name',
  sex: true,
  age: 12,
  asdf: '我是objI和objI2都不存在的属性,所以我会波浪线提示'
}

三、类型浅谈

any

any包含所有的值,可以对其做任何操作,尽量避免使用。

let a:any = 666
let b:any = ['danger']
let c = a + b // 正常这样会报错,但是设置类型为any后,这里并不会报错

unknown

与any类似,也表示任何值,但是ts会要求你再做检查,细化类型。

const a:unknown = 1
// const b = a + 10 // 会红色波浪线提示,运算符+不能用于unknown和10
if (typeof a === 'number') { // 提前判断下,下方才不会报错
  const b = a + 10
}

boolean

总共有两个值:true和false

let a = true // boolean
let b:boolean = true // boolean
// 可以明确的告诉ts,该值为某具体的布尔值
const c = true // true
const d:true = true // true
const e:true = false // 会波浪线提示
// c = false // 波浪线提示,c是一个常数,不可修改
a = false // 正常执行

number

同js,包括所有的数字(注意,大于2的53次方的数字,精度可能会丢失)

let a = 2
a = '2' // 会波浪线提示,字符串不可赋值给number
let a = 9999999999999999
console.log('-------->', a, 2**53) // 10000000000000000 9007199254740992  a的精度丢失少了1

bigint

bigint是js和ts新引入的类型,在处理较大整数(超出2的53次方时)时,不用再担心舍入误差。

let a = 9999999999999999n
console.log('-------->', a) // 9999999999999999n

string

同js,也可以明确指定具体值

let a: 'john' = 'zoe' // 波浪线提示
let b: 'john' = 'john' // 正常执行,同const
b = 'zoe' // 波浪线提示

symbol

符号,不太常用

对象

object (注意o是小写的)

object仅比any的范围窄一些,但也窄不了多少,object对值知之甚少,只能表示该值是一个javaScript对象

let danger:object = {}
danger = null // 正常执行
danger = undefined // 正常执行
danger = { x: 1 } // 正常执行
danger = [] // 正常执行
danger = 2 // 波浪线提示
danger = '我是字符串' // 波浪线提示

let a: object = {
  b: 'x'
}
console.log(a.b)

会波浪线提示
image.png
如果不显式注解,ts会主动推导对象的结构,也可以在{}里明确描叙

let a = {
  b: 'x'
}
let c: {d: string} = {
  d: 'x'
}
console.log(a.b)
console.log(c.d)

前面有说const会对推导结果有影响,object不同,const并不会导致ts把推导的类型缩窄,这是因为js对象是可变的,所以在ts看来,创建对象后,你可能会更新对象的字段

const a = {
  b: 'x'
}
a.b = 'y' // 正常执行

const b = 2
b = 3 // 会波浪线提示

告诉ts某个属性是可选的,加修饰符?

let c: { d: string, e: number } = {
  d: 'x'
} // 会波浪线提示,因为e是必选的属性
let d: { d: string, e?: number } = {
  d: 'x'
} // 正常执行,因为e后面加了个可选标志,所以e是可有可无的

告诉ts实际属性比计划的多

interface aI {
  b: number,
  [key: string]: boolean | number
}
let a: aI = {
  b: 1,
  d: true,  // 多了d属性,正常执行
  e: '我是string, 这里会波浪线提示,因为[key: string]: boolean | number 里定义好了,只能为boolean和number'
}

[key: T]: U 这种写法叫索引签名,key可以为任意值,T必须可赋值给number或string,U的类型中必须包含整个object里的所有类型 修饰符readonly

interface objI {
  readonly b: string
}
let obj: objI = {
  b: '1'
}
obj.b = '我会波浪线提示,因为我是readonly,不可修改'

空对象类型{}

任何类型都可以赋值给空对象类型,比object(o小写)还要宽些,尽量避免使用该类型

let danger = {}
danger = null
danger = undefined
danger = { x: 1 }
danger = []
danger = 2
danger = '此块代码全部正常执行'

Object(注意O是大写的)

同{},尽量避免使用

数组

ts支持两种注解数组类型的语法:T[]Array<T>,两者的作用等同

let a: Array<number> = [1]
let b: number[] = [1]

元组

元组是数组的子类型,是定义数组的一种特殊方式,长度固定,各索引位上的值具有固定的已知类型

let a: [number, string] = [1, '我是固定长度为2的元组,不能超过这个长度,否则会波浪线提示']
let b: [number, string?] = [1, '我是可选的元素,所以此元组的长度可以为1,也可以为2']
let c: [string, boolean, ...string[]] = ['a', true, '元组支持剩余元素,即为元组定义最小长度,且剩下的其他元素类型定义为string']

enum

枚举,和object很像,但不可修改

// 注意首字母要大写
const enum Meijun {
  Color = 'red',
  Size = '24px'
}
let b = Meijun.Color // Meijun  red
b = '会波浪线提示,因为不可修改,只能读取Meijun里的值'

其他类型

null: 缺少值
undefined:尚未赋值的变量
void: 没有return语句的函数
never:永不返回的函数(基本不用)

function a() {
  return '这是一个返回string的函数,隐式注解'
}
function aa():string {
  return '这是一个返回string的函数, 显式注解'
}
function b() {
  const str = '这是一个返回void的函数,隐式注解'
}
function bb() {
  const str = '这是一个返回void的函数,显式注解'
}
function c(): never {
  throw TypeError('这是一个返回never的函数')
}
function d(): never {
  while (true) {
    console.log('这是一个返回never的函数')
  }
}

四、函数

1、声明和调用函数

多数情况下,ts无法推导出参数的类型,因此,我们会显示注解函数的参数。其余同js.

const fun = (a: number, b: number) => {
  return a*b
}

返回类型能推导出来,不过也可以显示注解

const fun = (a: number, b: number): number => {
  return a*b
}

可选和默认的参数

和object一样,可以使用修饰符?标记参数为可选的,申明参数时,必要的参数放前面,可选的放后面

const fun = (a: string, b?: string) => {
  return a || b
}
fun('我是必传的参数,不传会波浪线提示', '可选参数,传或不传,都不会提示')
const fun = (a: string = '虽然我是必传的参数,但是我有默认值,所以下方不传,也不会波浪线提示', b?: string) => {
  return a || b
}
fun()

剩余参数

参数的具体数量无法确定,此时需要用剩余参数

// 错误示例:
(() => {
  const fun = (a: string, ...arguments) => {
    console.log('==========>', a, ...arguments)
  }
  fun('使用js的剩余参数方法,虽然此时不会此时不会波浪线提示,但是在运行时,会报错', 2)
})()

image.png

// 正确示例:
const fun = (a: number, ...numbers: number[]) => {
  console.log('==========1>', a, numbers)
}
// 函数调用
fun(1, 2, 3)

image.png

函数调用

const fun = (a: string, ...numbers: number[]) => {
  console.log('==========1>', a, ...numbers)
}
fun('我是圆括号调用,最常用的调用方法', 1)
fun.apply(null, ['apply调用,为函数内部的this绑定一个值,然后展开第二个参数(数组形式),传给要调用的函数', 2])
fun.call(null, ['call调用,和apply类似,不过是按照顺序应用参数,而不做展开', 3])
fun.bind(null, ['bind调用,和call类似,不过并不调用函数,而是返回一个新的函数,让我们继续用上方方法去调用', 4])()

image.png

持续更新中。。。