一、TypeScript中的类型运算符
1、typeof 运算符
typeof 获取变量或表达式的类型
let num = 1
type NumType = typeof num
let a: NumType = 12 // success
a = 'hello' // error
2、keyof 运算符
keyof 获取对象类型的所有键,并将其作为联合类型返回。
interface Dog {
name: string
age: number
}
type DogKeys = keyof Dog // 'name' | 'age'
let dog: DogKeys = 'name' // success
let dog2: DogKeys = 'age' // success
let dog3: DogKeys = 'gender' // error
3、方括号运算符
方括号运算符用于从对象类型中获取特定属性的类型。
interface Dog {
name: string
age: number
}
type NameType = Dog['name'] // string
const name: NameType = 'dog' // success
const name1: NameType = 123 // error
4、in 运算符
in 运算符有两种用法,第一种是用来确定对象是否包含某个属性名。第二种是用来遍历联合类型的每一个成员类型。
// in 用来确定对象是否包含某个属性名。
const obj = { a: 'hello world' }
'a' in obj ? console.log('find a') : console.log('not find a') // find a
'b' in obj ? console.log('find b') : console.log('not find b') // not find b
// in 用来取出(遍历)联合类型的每一个成员类型。
type Keys = 'name' | 'age'
type Person = {
[K in Keys]: string
} // 等同于 { name: string, age: string }
const person: Person = {
name: '张三',
age: '18'
}
5、extends 运算符
extends 用于约束泛型类型或在条件类型中使用
// 用于约束泛型类型
function identity<T extends number | string>(value: T): T {
return value
}
identity('123') // success
identity(123) // success
identity(true) // error
// 用于在条件类型中使用
type IsString<T> = T extends string ? true : false
const a = '123'
const isString: IsString<typeof a> = true // success
6、infer 关键字
infer 主要用来定义泛型里面推断出来的类型参数,而不是外部传入的类型参数。例如,在处理函数类型时,你可能希望提取参数类型或返回值类型、提取数组元素类型。也可以提取对象属性类型。
// 提取返回值类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
function exampleFunction() {
return 'Hello, World!'
}
type ExampleReturnType = ReturnType<typeof exampleFunction> // string
const a: ExampleReturnType = 'hello world' //success
const a0: ExampleReturnType = 1 // error
// 提取参数类型
type ArgsType<T> = T extends (...args: (infer R)[]) => string ? R : never
function exampleFunction1(num: number) {
return 'Hello, World!'
}
type ExampleReturnType1 = ArgsType<typeof exampleFunction1> // string
const a1: ExampleReturnType1 = 1 // success
const a2: ExampleReturnType1 = 'hello world' // error
// 提取数组元素类型
type ElementType<T> = T extends (infer U)[] ? U : never
type StringArray = string[]
type StringElement = ElementType<StringArray> // string
const a3: StringElement = 'hello world' // success
const a4: StringElement = 1 // error
7、is 运算符
is 函数返回布尔值的时候,可以使用is运算符,限定返回值与参数之间的关系。
interface Dog {
run: () => void
}
interface Pig {
sleep: () => void
}
function isFish(T: Dog | Pig): T is Dog {
return (T as Dog).run !== undefined
}
const flag = isFish({ run: () => {} }) // true
const flag2 = isFish({ sleep: () => {} }) // false
8、模板字符串
TypeScript 允许使用模板字符串,构建类型。模板字符串的最大特点,就是内部可以引用其他类型,包含string、number、bigint、boolean、null、undefined。如果引入这六种以外的类型会报错。模板字符串也可以引入联合类型,如果引入联合类型则会展开联合类型,如引入多个联合类型则会交叉展开联合类型
type num = 1
type Greeting = `hello ${num}` // "hello 1"
const a: Greeting = `hello 1` // success
const a1: Greeting = `hello 123` // error
// 引入其他类型会报错
type hello = 'hello'
type Obj = { a: "world" }
type T1 = `${hello}` // success
type T2 = `${Obj}` // error
// 展开联合类型
type T = 'A' | 'B'
type U = 'C' | 'D'
type V = `${T}_123_${U}` // "A_123_C"|"A_123_D"|"B_123_C"|"B_123_D"
const a3: V = 'A_123_C' // success
const a4: V = 'B_123_C' // success
const a5: V = 'a_123_c' // error
二、类型工具InstanceType
1、InstanceType 的基本用法
InstanceType是一个内置的高级类型工具,用于获取构造函数的实例类型。它接受一个构造函数类型作为参数,并返回该构造函数创建的实例的类型。
class Dog {
name: string
constructor(name: string) {
this.name = name
}
run() {
console.log(`${this.name} run`)
}
}
type DogType = InstanceType<typeof Dog>
const Tom: DogType = new Dog('tom')
console.log(Tom.name) // tom
Tom.run() // tom run
2、在vue3+Ts中的使用InstanceType
在 vue3 + Ts + Element Plus 的项目中,我们经常会使用ref去获取Element Plus组件内部的方法,如果只是正常使用ref没有任何代码提示,非常的难受。这里我们就可以用InstanceType配合typeof来解决这问题。代码如下:
<template>
<div class="box">
<el-table ref="tableRef" :data="tableData" row-key="id" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
<el-button type="primary" @click="selectFirst">选中第一行</el-button>
<el-button type="primary" @click="cancelFirst">取消选中</el-button>
</div>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import { ElTable } from 'element-plus'
const tableData = reactive([
{
id: '1',
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: '2',
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}
])
const tableRef = ref<InstanceType<typeof ElTable>>()
const selectFirst = () => {
tableRef.value?.toggleRowSelection(tableData[0], true)
}
const cancelFirst = () => {
tableRef.value?.clearSelection()
}
</script>
<style lang="scss" scoped></style>
其他的组件也可以使用该方法,例如ElForm组件。但是ElForm组件Element Plus官方也提供了一个类型别名FormInstance去解决代码提示问题。实现的原理都是一样的,具体可以看Element Plus官方文档和源码。
3、封装自定义Hooks
上面我们介绍了在 vue3 + Ts + Element Plus 的项目中使用InstanceType,但是每次都要重复的写这段代码,非常的麻烦。这里我们需要把它封装成一个公共的Hooks方便我们在项目中使用,减少冗余的代码。
hooks代码如下:
import { ref } from 'vue'
export default function useTypeRef<T extends abstract new (...args: any[]) => any>(_Comp: T) {
return ref<InstanceType<T>>()
}
T extends 这表示 T 是一个泛型参数,并且它需要满足某种特定的类型条件。
abstract 这表示T 必须是一个抽象类的构造函数类型。
new (...args: any[]) => any 中new 表示这是一个构造函数。(...args: any[]) 表示构造函数可以接受任意数量、任意类型的参数。=> any 表示构造函数返回一个任意类型的实例。
<template>
<div class="box">
<el-table ref="tableRef" :data="tableData" row-key="id" style="width: 100%">
<el-table-column type="selection" width="55" />
<el-table-column prop="date" label="日期" width="180" />
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
<el-button type="primary" @click="selectFirst">选中第一行</el-button>
<el-button type="primary" @click="cancelFirst">取消选中</el-button>
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue'
import { ElTable } from 'element-plus'
import useTypeRef from '@/hooks/useTypeRef'
const tableData = reactive([
{
id: '1',
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
},
{
id: '2',
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}
])
const tableRef = useTypeRef(ElTable)
const selectFirst = () => {
tableRef.value?.toggleRowSelection(tableData[0], true)
}
const cancelFirst = () => {
tableRef.value?.clearSelection()
}
</script>
<style lang="scss" scoped></style>
三、最后
文章在这里就结束了,有任何不准确的地方请多多指正,希望各位大佬勿喷。感谢你的阅读,愿你在技术探索的路上不断前行,一起加油!