[TS] 项目中的 Ts 使用技巧

[TS] 项目中的 Ts 使用技巧

·

2 min read

现在我写项目基本上都是用ts了,但是对于一些ts的机制还是比较模糊,所以写一篇博客学习一下

一些特殊类型

先来讲一讲ts中的特殊类型,有利于理解ts的类型推断

1. never 类型

never表示不存在的类型,在ts无法推断类型时,可能会将类型推断为never,例如:

type Mentor = {
  name: string,
  age: number
}
​
const mentor = reactive<Mentor>({} as Mentor)
​
/**
 * 这里的本意是 key 是 Mentor 的字段名,value 的类型是字段所对应的类型
 * 但是由于 key 的类型是联合类型,所以 key 的类型是不确定的
 * 所以此处 ts 会将 mentor[key] 推断为 never 类型
*/
const editMentor = (key: keyof Mentor, value: Mentor[typeof key]) => {
  mentor[key] // 
}

2. any 类型

ts中,any表示任意值,所以任意的类型都可以赋值给any

使用any类型的对象时,即使使用了它身上的不存在的属性或者方法,也不会报错

类型断言 as 的使用规则

在类型为联合类型时,可以用as将其断言为更确切的类型:

let someValue: any = "this is a string"
let strLength: number = (someValue as string).length

使用as可以将类型断言为更大的类型(断言后的类型必须包括前者),但是不能断言为没有交集的类型:

type Mentor = {
  name: string,
  age: number
}
​
// 原本 mentor 的类型为 {},断言后为 Mentor,Mentor 类型包含了 {} 类型,是可以的
const mentor = reactive<Mentor>({} as Mentor)

使用 ts 为 localStorage 封装类型校验

存储localStorage时,使用getItem获取值时,默认是没有类型提示的,每次都要去看一次某个对象有什么字段,所以我们手动封装一个类,以便我们使用getItem时,有类型提示,会更方便

  • 封装一个LocalStorage类:
class LocalStorage {
  // 单例模式
  private instance: Storage
​
  constructor() {
    this.instance = window.localStorage
  }
​
  // 调用 getItem 时传入声明的类型,获取类型提示
  getItem<T>(key: string) {
    const value = this.instance.getItem(key)
    if(value) {
      const obj: T = JSON.parse(value)
      return obj
    }
    return null
  }
​
  setItem(key: string, value: any) {
    this.instance.setItem(key, JSON.stringify(value))
  }
​
  removeItem(key: string) {
    this.instance.removeItem(key)
  } 
}
​
export default LocalStorage
  • 在组件中使用:
<script setup lang="ts">
import LocalStorage from "@/utils/local-storage.ts"
import { onMounted, ref } from "vue"const localStorage = new LocalStorage()
​
interface Student {
  name: string,
  age: number,
}
const student: Student = {
  name: "lordmoon",
  age: 20,
}
​
const showStu = ref<Student>()
​
onMounted(() => {
  // 调用 getItem 时传入声明的类型
  let stu = localStorage.getItem<Student>("student")
  if(!stu) {
    localStorage.setItem("student", student)
    stu = localStorage.getItem<Student>("student")
  }
  showStu.value = stu!
})
</script>
​
<template>
  <div class="container">
    <div class="name">{{ showStu?.name }}</div>
    <div class="age">{{ showStu?.age }}</div>
  </div>
</template>
​
<style lang="scss">
​
</style>

跨组件修改对象的某个字段

有时候我们会将一个对象通过props传到一个组件中,来渲染表格;如果我们想要在该组件中修改这个对象的某个字段,我们可以将你要修改的该对象的keyvalue传回到父组件

但是这就有一个问题,你如何确保参数的类型校验正确呢?既然都用到ts了,总不能像js那样什么类型都不校验吧

这里就可以用到tskeyofextends关键字了:

type Mentor = {
  name: string,
  age: number
}
​
const mentor = reactive<Mentor>({} as Mentor)
​
const editMentor = <K extends keyof Mentor> (key: K, value: Mentor[K]) => {
  mentor[key] = value
}
​
editMentor('name', 'lordmoon')
editMentor('age', 20)