ts学习摘录1

33 阅读6分钟

摘自coderwhy的ts教程

单个类型

类型推导

  • let进行类型推导, 推导出来的通用类型
  • const进行类型推导, 推导出来的字面量类型

数组类型注解

let nums: Array<number> = [123, 321, 111]
let names: string[] = ["abc", "cba", "nba"]

函数类型

  • 定义函数参数和返回值
// 定义对象类型
type LyricType = {
  time: number
  text: string
}

// 歌词解析工具
function parseLyric(lyric: string): LyricType[] {
  const lyrics: LyricType[] = []
  lyrics.push({ time: 1111, text: "天空想要下雨" })
  return lyrics
}
  • 匿名函数最好不要添加类型注解
const names: string[] = ["abc", "cba", "nba"]
names.forEach(function(item, index, arr) {
  console.log(item, index, arr)
})

unknown

  • unknown类型 必须进行类型的校验(缩小), 才能根据缩小之后的类型, 进行对应的操作
let foo: unknown = "aaa"
foo = 123 // 赋值操作不会报错 但如果是 foo.length这种会报错

if (typeof foo === "string") { // 类型缩小
  console.log(foo.length, foo.split(" "))
}

void

  • 一个函数没有返回值, 那么返回值的类型就是void类型
// 1.定义要求传入的函数的类型
type ExecFnType = (...args: any[]) => void

// 2.定义一个函数, 并且接收的参数也是一个函数, 而且这个函数的类型必须是ExecFnType
function delayExecFn(fn: ExecFnType) {
  setTimeout(() => {
    fn("why", 18)
  }, 1000);
}

// 3.执行上面函数, 并且传入一个匿名函数
delayExecFn((name, age) => {
  console.log(name, age)
})

tuple元组

  • 数组里每个位置类型不同
  • 常用于函数返回多个值时,指明返回值类型
const info3: [string, number, number] = ["why", 18, 1.88]
const value2 = info3[2]

// 在函数中使用元组类型是最多的(函数的返回值)
function useState(initialState: number): [number, (newValue: number) => void] {
  let stateValue = initialState
  function setValue(newValue: number) {
    stateValue = newValue
  }

  return [stateValue, setValue]
}
const [count, setCount] = useState(10)
console.log(count)
setCount(100)

类型断言

  • xx as 类型
  • 断言只能断言成更加具体的类型, 或者 不太具体(any/unknown) 类型
const imgEl = document.querySelector(".img") as HTMLImageElement
imgEl.src = "xxx"
imgEl.alt = "yyy"

非空断言

  • 使用含有 可选属性的对象类型 对可选属性直接操作时
// 可选属性
interface IPerson {
  name: string
  age: number
  friend?: {
    name: string
  }
}

const info: IPerson = {
  name: "why",
  age: 18
}

// 访问属性: 可选链: ?.
console.log(info.friend?.name)

// 属性赋值:
// 解决方案一: 类型缩小
if (info.friend) {
  info.friend.name = "kobe"
}

// 解决方案二: 非空类型断言(有点危险, 只有确保friend一定有值的情况, 才能使用)
info.friend!.name = "james"

字面量类型

  • const基本类型,即被认为是字面量类型
  • 常和联合类型搭配用,锁定值的可选范围
  • 如果要用变量填充,靠断言得了
const name: "why" = "why"
const name = "why"//和上面等价

//字面量联合
type MethodType = "get" | "post"
function request(url: string, method: MethodType) {
}

request("http://codfasda.com/api/aaa", "post")
//-----------------------------------------
const info = {
  url: "xxxx",
  method: "post"
}
// 下面的做法是错误: info.method获取的是string类型
request(info.url, info.method)

// 解决方案一: info.method进行类型断言
request(info.url, info.method as "post")

// 解决方案二: 直接让info对象类型是一个字面量类型
const info2: { url: string, method: "post" } = {
  url: "xxxx",
  method: "post"
}

// 解决方案三 (const 声明的变量 就是字面量类型,对象不太一样 还得 as const)了解即可
const info2 = {
  url: "xxxx",
  method: "post"
} as const

request(info2.url, info2.method)

类型复合

联合类型

function printID(id: number | string) {
  console.log("您的ID:", id)

  // 类型缩小
  if (typeof id === "string") {
    console.log(id.length)
  } else {
    console.log(id)
  }
}

printID("abc")
printID(123)

类型别名

type IDType = number | string

function printID(id: IDType) {
  console.log(id)
}

type PointType = { x: number, y: number, z?: number }
function printCoordinate(point: PointType) {
  console.log(point.x, point.y, point.z)
}

接口

interface PointType2 {
  x: number
  y: number
  z?: number
}

别名 和 接口 的区别

结论:如果是非对象类型的定义使用type, 如果是对象类型的声明那么使用interface

  1. type类型使用范围更广, 接口类型只能用来声明对象
  2. 声明对象时, interface同名会合并type不允许两个相同名称的别名同时存在
  3. interface支持继承
interface IPerson {
  name: string
  age: number
}

interface IKun extends IPerson {
  kouhao: string
}

const ikun1: IKun = {
  kouhao: "你干嘛, 哎呦",
  name: "kobe",
  age: 30
}

交叉类型

  • 两种(多种)类型要同时满足
type NewType = number & string // 没有意义 推断出来是never

interface IKun {
  name: string
  age: number
}

interface ICoder {
  name: string
  coding: () => void
}

type InfoType = IKun & ICoder

// info必须含有这俩接口的所有属性,不然报错
const info: InfoType = {
  name: "why",
  age: 18,
  coding: function() {
    console.log("coding")
  }
}

和它相对的是 联合类型 type ID = number | string

类型缩小

变量是联合类型,且具体处理时要缩小到某个类型时 进行下面这些操作

  • typeof
  • instanceof
  • === / !==
  • switch
  • key in obj 【obj具有的属性不确定时】
// 1.typeof: 使用的最多
function printID(id: number | string) {
  if (typeof id === "string") {
    console.log(id.length, id.split(" "))
  } else {
    console.log(id)
  }
}


// 2.===/!==: 方向的类型判断
type Direction = "left" | "right" | "up" | "down"
function switchDirection(direction: Direction) {
  if (direction === "left") {
    console.log("左:", "角色向左移动")
  } else if (direction === "right") {
    console.log("右:", "角色向右移动")
  } else if (direction === "up") {
    console.log("上:", "角色向上移动")
  } else if (direction === "down") {
    console.log("下:", "角色向下移动")
  }
}


// 3. instanceof: 传入一个日期, 打印日期
function printDate(date: string | Date) {
  if (date instanceof Date) {
    console.log(date.getTime())
  } else {
    console.log(date)
  }

  // if (typeof date === "string") {
  //   console.log(date)
  // } else {
  //   console.log(date.getTime())
  // }
}


// 4.in: 判断是否有某一个属性
interface ISwim {
  swim: () => void
}

interface IRun {
  run: () => void
}

function move(animal: ISwim | IRun) {
  if ("swim" in animal) {
    animal.swim()
  } else if ("run" in animal) {
    animal.run()
  }
}

const fish: ISwim = {
  swim: function() {}
}

const dog: IRun = {
  run: function() {}
}

move(fish)
move(dog)

函数类型

基础声明

  • 当用函数变量时 (函数作为参数/变量当函数)最好用type定义函数类型
  • 函数类型要求的参数多,但函数实例 少参数也没事 调用时多传入的参数被忽略
  • 类型定义的函数,只能被多传参,不能少传参
type CalcType = (num1: number, num2: number) => number

const sumS:CalcType=(num1)=>{
  return num1
}

function sumT(num1: number, num2: number) {
  return num1 + num2
}

function mul(num1: number, num2: number) {
  return num1 * num2
}

function calc(calcFn: CalcType) {
  const num1 = 10
  const num2 = 20
  const res = calcFn(num1, num2)
  console.log(res)
}

calc(sumS)
calc(sumT)
calc(mul)

可选参数

// 可选参数类型是什么? number | undefined 联合类型
function foo(x: number, y?: number) {
  if (y !== undefined) {
    console.log(y + 10)
  }
}

foo(10)
foo(10, 20)

默认值

// 1.有默认值的情况下, 参数的类型注解可以省略
// 2.有默认值的参数, 是可以接收一个undefined的值
function foo(x: number, y = 100) {
  console.log(y + 10)
}

foo(10)
foo(10, undefined)
foo(10, 55)

剩余参数

function foo(...args: (string | number)[]) {

}

foo(123, 321)
foo("abc", 111, "cba")

函数重载

  • 当函数的参数类型和返回值类型 有多种对应关系时用
// 1.先编写重载签名
function add(arg1: number, arg2: number): number
function add(arg1: string, arg2: string): string

// 2.编写通用的函数实现
function add(arg1: any, arg2: any): any {
  return arg1 + arg2
}

add(10, 20)
add("aaa", "bbb")

联合类型

  • 也是针对参数类型不唯一的情况,能用联合类型的场景尽量使用联合类型 不用函数重载
function getLength(arg: string | any[]) {
  return arg.length
}

函数中的this

  • 没有对TS进行特殊配置的情况下, this是any类型
  • //比较复杂 用到的时候再看