【总结】Typescript 结合Vue3的写法

目录

前言

一、结合写法

1. ref

2. reactive

3. defineProps

4. defineEmits

5. computed

6. 事件处理函数

7. html元素引用

8. 组件实例

二、拓展补充

1. keyof 操作符

2. typeof 操作符

3. InstanceType 工具类型


前言

Vue 3与TypeScript结合使用能够提供类型检查和智能提示,增强了代码的可靠性和可维护性。本文整理了项目开发时用到的结合写法,供学习和参考。

一、结合写法

1. ref

在原有的 ref() 之间加 <> ,并且在 <> 里跟ts类型。

ref() 也会隐式地从它的参数中推导类型。

const msg = ref<string>('hello')
​
import type { Ref } from 'vue'
const msg2: Ref<number> = ref(100)
​
type Todo = {
  id: number
  name: string
  done: boolean
}
const list = ref<Todo[]>([])
​
const list: Ref<Todo[]> = ref([])

2. reactive

在声明变量时,在 : 后跟ts类型。

reactive() 也会隐式地从它的参数中推导类型。

import { reactive } from 'vue'
​
// 推导得到的类型:{ title: string }
const book = reactive({ title: 'Vue 3 指引' })

​要显式地标注一个 reactive 变量的类型,我们可以使用接口

import { reactive } from 'vue'
​
interface Book {
  title: string
  year?: number
}
​
const book: Book = reactive({ title: 'Vue 3 指引' })

​不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。

3. defineProps

在原有的 defineProps() 之间加 <> ,并且在 <> 里跟ts类型。

// 注意这种方式无法设置可选参数的默认值
const props = defineProps<{
  name?: string
  phoneNumber: number
  userInfo: object
  tags: string[]
}>()

// 指定默认值
withDefaults(defineProps<{
  size?: number
  labels?: string[]
}>(), {
  size: 3,
  labels: () => ['default label']
})

上面写法太笨拙,可以使用 响应式语法糖 解构 + defineProps 就行

注意:目前需要 显式地选择开启 ,因为它还是一个实验性特性。

// vite.config.ts
export default defineConfig({
  plugins: [
    vue({
      reactivityTransform: true,
    }),
  ],
});
​
const { money, car = "宝马车" } = defineProps<{
  money: number
  car?: string
}>();

4. defineEmits

在原有的 defineEmits() 之间加 <> ,并且在 <> 里跟ts类型。

const emit = defineEmits(['change'])
const handleChange = () => {
  emit('change', 'itcast', '你好')
}
​
interface Emits {
  (e: "update:modelValue", value: string): void;
  (e: "change", value: string): void;
}
//定义控件事件
const emit = defineEmits<Emits>();
​
// 基于类型的声明
const emit = defineEmits<{
  (e: 'change', id: number): void;
  (e: 'update', value: string): void;
}>()

5. computed

computed() 会自动从其计算函数的返回值上推导出类型:

import { ref, computed } from 'vue'
​
const count = ref(0)
​
// 推导得到的类型:ComputedRef<number>
const double = computed(() => count.value * 2)
​
// => TS Error: Property 'split' does not exist on type 'number'
const result = double.value.split('')

​你还可以通过泛型参数显式指定类型:

const double = computed<number>(() => {
  // 若返回值不是 number 类型则会报错
})

6. 事件处理函数

<script setup lang="ts">
function handleChange(event) {
  // `event` 隐式地标注为 `any` 类型
  console.log(event.target.value)
}
</script>
​
<template>
  <input type="text" @change="handleChange" />
</template>

​没有类型标注时,这个 event 参数会隐式地标注为 any 类型。这也会在 tsconfig.json 中配置了 "strict": true"noImplicitAny": true 时报出一个 TS 错误。因此,建议显式地为事件处理函数的参数标注类型。此外,你可能需要显式地强制转换 event 上的属性:

function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
}

7. html元素引用

模板引用需要通过一个显式指定的泛型参数和一个初始值 null 来创建:

<script setup lang="ts">
import { ref, onMounted } from 'vue'
​
const el = ref<HTMLInputElement | null>(null)
​
onMounted(() => {
  el.value?.focus()
})
</script>
​
<template>
  <input ref="el" />
</template>

8. 组件实例

<!-- MyModal.vue -->
<script setup lang="ts">
import { ref } from 'vue'
​
const isContentShown = ref(false)
const open = () => (isContentShown.value = true)
​
defineExpose({
  open
})
</script>

为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:

<!-- App.vue -->
<script setup lang="ts">
import MyModal from './MyModal.vue'
​
const modal = ref<InstanceType<typeof MyModal> | null>(null)
​
const openModal = () => {
  modal.value?.open()
}
</script>

二、拓展补充

1. keyof 操作符

通过索引类型查询能够获取给定类型中的属性名类型。索引类型查询的结果是由字符串字面量类型构成的联合类型,该联合类型中的每个字符串字面量类型都表示一个属性名类型。

type Point = { x: number; y: number };
type P = keyof Point; // type P = 'x' | 'y'

​如果类型具有字符串或数字索引签名,则 keyof 将返回这些类型:

type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish; // type A = number
​
type Mapish = { [k: string]: boolean };
type M = keyof Mapish; // type M = string | number
type Todo = {
  id: number;
  text: string;
  done: boolean;
}
​
const todo: Todo = {
  id: 1,
  text: "Learn TypeScript keyof",
  done: false
}
// extends 关键字约束 K 类型必须为 keyof T 联合类型的子类型。 'id' | 'text' | 'done'
function prop<T extends object, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
​
const id = prop(todo, "id"); // const id: number
const text = prop(todo, "text"); // const text: string
const done = prop(todo, "done"); // const done: boolean

2. typeof 操作符

用于获取一个值的类型信息。typeof操作符有两种主要的使用方式:

  • typeof表达式:用于获取一个值的类型字符串。
const num = 42;
const typeOfNum = typeof num; // 类型为 "number"

const obj = { name: 'Alice', age: 25 };
const typeOfObj = typeof obj; // 类型为 "object"

注意:typeof操作符返回的是一个字符串字面量,表示该值的类型。常见的返回值包括 "number"、"string"、"boolean"、"object"、"function"等。

  • typeof类型守卫:用于在条件语句中判断一个变量的类型。
function printLength(value: string | number) {
  if (typeof value === 'string') {
    console.log(value.length); // 在这个条件块中,value被推断为 "string" 类型
  } else {
    console.log('Value is not a string.');
  }
}

在上述代码中,通过使用typeof进行类型检查,可以在不使用显式类型断言的情况下,根据不同的类型执行不同的代码逻辑。

需要注意的是,typeof操作符的结果在某些情况下可能比较特殊,例如:

  1. typeof null 的结果是 "object",这是由于历史原因造成的。
  2. 对于函数类型,typeof会返回 "function"。

3. InstanceType 工具类型

该工具类型能够获取构造函数的返回值类型,即实例类型。这里面的T必须是一个构造函数。

class C {
  x = 0;
}
type T0 = InstanceType<typeof C>;         // C

type T1 = InstanceType<new () => object>; // object

type T2 = InstanceType<any>;              // any

type T3 = InstanceType<never>;            // any

type T4 = InstanceType<string>;           // 编译错误
type T5 = InstanceType<Function>;         // 编译错误

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值