现在我写项目基本上都是用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
传到一个组件中,来渲染表格;如果我们想要在该组件中修改这个对象的某个字段,我们可以将你要修改的该对象的key
和value
传回到父组件
但是这就有一个问题,你如何确保参数的类型校验正确呢?既然都用到ts
了,总不能像js
那样什么类型都不校验吧
这里就可以用到ts
的keyof
和extends
关键字了:
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)