vue3与ts的组合式API

vue3与ts的组合式API

props

1.基本props
vue 复制代码
<script setup lang="ts">
const props = defineProps<{
  foo: string
  bar?: number
}>()
</script>
2.抽离props
vue 复制代码
<script setup lang="ts">
interface Props {
  foo: string
  bar?: number
}

const props = defineProps<Props>()
</script>
3.抽离和导入type
vue 复制代码
<script setup lang="ts">
import type { Props } from './foo'

const props = defineProps<Props>()
</script>
4.默认值props
tsx 复制代码
export interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})
5.复杂props
vue 复制代码
<script setup lang="ts">
interface Book {
  title: string
  author: string
  year: number
}

const props = defineProps<{
  book: Book
}>()
</script>

emits

一个类型字面量,其中键是事件名称,值是数组或元组类型,表示事件的附加接受参数。示例使用了具名元组,因此每个参数都可以有一个显式的名称。

vue 复制代码
<script setup lang="ts">
// 基于类型
const emit = defineEmits<{
  (e: 'change', id: number): void
  (e: 'update', value: string): void
}>()

// 3.3+: 可选的、更简洁的语法
const emit = defineEmits<{
  change: [id: number]
  update: [value: string]
}>()
</script>

ref()

1.自动推导
typescript 复制代码
import { ref } from 'vue'

// 推导出的类型:Ref<number>
const year = ref(2020)

// => TS Error: Type 'string' is not assignable to type 'number'.
year.value = '2020'
2.复杂ref
typescript 复制代码
import { ref } from 'vue'
import type { Ref } from 'vue'

const year: Ref<string | number> = ref('2020')

year.value = 2020 // 成功!

个人建议使用第二种,字少了,且无需导入import type { Ref } from 'vue'

typescript 复制代码
// 得到的类型:Ref<string | number>
const year = ref<string | number>('2020')

year.value = 2020 // 成功!

注意:如果你指定了一个泛型参数但没有给出初始值 ,那么最后得到的就将是一个包含 undefined 的联合类型:

typescript 复制代码
// 推导得到的类型:Ref<number | undefined>
const n = ref<number>()

recative()

1.自动推导
typescript 复制代码
import { reactive } from 'vue'

// 推导得到的类型:{ title: string }
const book = reactive({ title: 'Vue 3 指引' })
2.复杂reactive
typescript 复制代码
import { reactive } from 'vue'

interface Book {
  title: string
  year?: number
}

const book: Book = reactive({ title: 'Vue 3 指引' })

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

错误示例:

typescript 复制代码
import { reactive } from 'vue'

interface Book {
  title: string;
  year?: number;
}

// 不推荐:使用了泛型参数,但返回的类型与Book不同
const book: Book = reactive<Book>({ title: 'Vue 3 指引' });

正确示例,使用toRefs()

typescript 复制代码
import { reactive, toRefs } from 'vue'

interface Book {
  title: string;
  year?: number;
}

// 创建一个响应式的Book对象
const bookReactive = reactive({ title: 'Vue 3 指引' });

// 使用toRefs()将每个属性转换为Ref,确保类型安全
const bookRefs = toRefs(bookReactive);

// 现在bookRefs是一个Record类型,其中的属性具有与Book相同的类型
const book: { title: Ref<string>; year?: Ref<number | undefined> } = bookRefs;

// 或者,如果你知道你只会在模板中使用,可以使用类型断言
const bookWithAssertion = {
  title: bookRefs.title as Ref<string>,
  year: bookRefs.year as Ref<number | undefined>,
} as const;

computed()

1.自动推导
typescript 复制代码
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('')
2.显式指定
typescript 复制代码
const double = computed<number>(() => {
  // 若返回值不是 number 类型则会报错
})

为事件处理函数标注类型

**在处理原生 DOM 事件时,应该为我们传递给事件处理函数的参数正确地标注类型。**让我们看一下这个例子:

typescript 复制代码
<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 上的属性时可能需要使用类型断言:

typescript 复制代码
function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
}

为 provide / inject 标注类型

typescript 复制代码
const foo = inject<string>('foo') // 类型:string | undefined ???

为模板引用标注类型

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

typescript 复制代码
<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>

可以通过类似于 MDN 的页面来获取正确的 DOM 接口。https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLInputElement

注意为了严格的类型安全,有必要在访问 el.value 时使用可选链或类型守卫。这是因为直到组件被挂载前,这个 ref 的值都是初始的 null,并且在由于 v-if 的行为将引用的元素卸载时也可以被设置为 null

为组件模板引用标注类型

有时,你可能需要为一个子组件添加一个模板引用,以便调用它公开的方法。举例来说,我们有一个 MyModal 子组件,它有一个打开模态框的方法:

vue 复制代码
<!-- 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 工具类型来获取其实例类型:

vue 复制代码
<!-- 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>

如果组件的具体类型无法获得,或者你并不关心组件的具体类型,那么可以使用 ComponentPublicInstance。这只会包含所有组件都共享的属性,比如 $el

typescript 复制代码
import { ref } from 'vue'
import type { ComponentPublicInstance } from 'vue'

const child = ref<ComponentPublicInstance | null>(null)

官网链接

相关推荐
高兴蛋炒饭3 分钟前
RouYi-Vue框架,环境搭建以及使用
前端·javascript·vue.js
m0_7482404430 分钟前
《通义千问AI落地—中》:前端实现
前端·人工智能·状态模式
ᥬ 小月亮35 分钟前
Vue中接入萤石等直播视频(更新中ing)
前端·javascript·vue.js
夜斗(dou)1 小时前
node.js文件压缩包解析,反馈解析进度,解析后的文件字节正常
开发语言·javascript·node.js
恩爸编程2 小时前
纯 HTML+CSS+JS 实现一个炫酷的圣诞树动画特效
javascript·css·html·圣诞树·圣诞树特效·圣诞树js实现·纯js实现圣诞树
呜呼~225142 小时前
前后端数据交互
java·vue.js·spring boot·前端框架·intellij-idea·交互·css3
神雕杨2 小时前
node js 过滤空白行
开发语言·前端·javascript
网络安全-杰克2 小时前
《网络对抗》—— Web基础
前端·网络
m0_748250742 小时前
2020数字中国创新大赛-虎符网络安全赛道丨Web Writeup
前端·安全·web安全
周伯通*2 小时前
策略模式以及优化
java·前端·策略模式