TypeScript 与组合式 API

官网TypeScript 与组合式 API

https://cn.vuejs.org/guide/typescript/composition-api.html

环境搭建 Vue3 + TS加粗样式

环境搭建这里就不详细介绍了,可以直接使用官方的方式创建

npm init vue@latest

这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:

✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formatting? … No / Yes
 
Scaffolding project in ./<your-project-name>...
Done.

如果不确定是否要开启某个功能,你可以直接按下回车键选择 No。在项目被创建后,通过以下步骤安装依赖并启动开发服务器:

cd <your-project-name>
npm install
npm run dev

这里就不做过多的讲解了,这篇文章的重点还是在 script setup typescript 结合使用上

一、ref()

ref()接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的 property .value。

1. 类型定义

function ref<T>(value: T): Ref<UnwrapRef<T>>
interface Ref<T> {
  value: T
}

2. 为 ref() 标注类型

ref() 标注类型有三种方式:

  • 通过泛型参数的形式来给 ref()增加类型
import { ref } from 'vue'
 
const initCode = ref<string | number>('200')
  • 如果是遇到复杂点的类型,可以自定义 interface 然后泛型参数的形式传入
import { ref } from 'vue'
 
interface User {
  name: string
  age: string | number
}
 
const user = ref<User>({
  name:'前端开发爱好者',
  age: 20
})

通过使用 Ref 这个类型为 ref 内的值指定一个更复杂的类型

import { ref } from 'vue'
import type { Ref } from 'vue'
 
const initCode: Ref<string | number> = ref('200')
  • 三种方式推荐
    比较推荐使用前两种方式,前两种方式其实都是以泛型的形式来标注类型的,第三种方式需要额外的引入:
import type { Ref } from 'vue'

二、reactive()

reactive() 返回一个对象的响应式代理。

1. 类型定义

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

2. 为 reactive() 标注类型

  • 直接给声明的变量添加类型
import { reactive } from 'vue'
 
interface User {
  name: string
  age: string | number
}
 
const user:User = reactive({
  name:"前端开发爱好者",
  age:'20'
})
  • 通过泛型参数的形式来给 reactive()增加类型
import { reactive } from 'vue'
 
interface User {
  name: string
  age: string | number
}
 
const user = reactive<User>({
  name:"前端开发爱好者",
  age:'20'
})

3. 两种方式推荐

不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。推荐直接给声明的变量添加类型。

三、computed ()

接受一个 getter 函数,返回一个只读的响应式 ref 对象,即 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。

1. 类型定义

// 只读
function computed<T>(
  getter: () => T,
  debuggerOptions?: DebuggerOptions
): Readonly<Ref<Readonly<T>>>
 
// 可写的
function computed<T>(
  options: {
    get: () => T
    set: (value: T) => void
  },
  debuggerOptions?: DebuggerOptions
): Ref<T>

2. 为 computed() 标注类型

computed()标注类型有两种方式:

  • 从其计算函数的返回值上推导出类型
import { ref, computed } from 'vue'
 
const count = ref<number>(0)
 
// 推导得到的类型:ComputedRef<string>
const user = computed(() => count.value + '前端开发爱好者')
  • 通过泛型参数显式指定 computed() 类型
const user = computed<string>(() => {
  // 若返回值不是 string 类型则会报错
  return '前端开发爱好者'
})

3. 两种方式推荐

自动推导类型虽然简单快捷,但是还是希望手动的去指定其类型,这样更加利于代码的可维护性,所以这里推荐大家使用通过泛型参数显式指定 computed() 类型

四、defineProps()

为了在声明 props 选项时获得完整的类型推断支持,我们可以使用 defineProps API,它将自动地在 script setup 中使用

1. 为 defineProps() 标注类型

  • 从它的参数中推导类型:
const props = defineProps({
  name: { type: String, required: true },
  age: Number
})
  • 通过泛型参数来定义 props 的类型
const props = defineProps<{
  name: string
  age?: number
}>()
  • 当然了,我们也可以把以上的泛型参数定义成一个单独的 interface
interface Props {
  name: string
  age?: number
}
 
const props = defineProps<Props>()

以上的两种方式虽然都可以很方便的标注类型, 但是失去了对 props 定义默认值的能力

目前官方也给出了解决方案,但是目前这个方案还处于实验性,并且需要显式地选择开启。

// vite.config.js
export default {
  plugins: [
    vue({
      reactivityTransform: true
    })
  ]
}

通过对 defineProps() 的响应性解构来添加默认值:

<script setup lang="ts">
interface Props {
  name: string
  age?: number
}
 
const { name = '前端开发爱好者', age = 100 } = defineProps<Props>()
</script>

五、defineEmits()

为了在声明 emits 选项时获得完整的类型推断支持,我们可以使用 defineEmits API,它将自动地在 script setup 中使用

1. 为 defineEmits() 标注类型

  • defineEmits() 标注类型直接推荐泛型形式
import type { GlobalTheme } from 'naive-ui'
 
const emit = defineEmits<{
  (e: 'setThemeColor', val: GlobalTheme): void
}>()

虽然官方还推荐了运行时自动推导的一种形式,但是本人不是很推荐

六、defineExpose()

defineExpose() 编译器宏来显式指定在 script setup 组件中要暴露出去的 property,使得父组件通过模板ref的方式获取到当前组件的实例

为 defineExpose() 标注类型

defineExpose() 类型推导直接使用参数类型自动推导即可

<script setup>
import { ref } from 'vue'
 
const name = ref<string>('前端开发爱好者')
 
defineExpose({
  name
})

七、provide()

provide()供给一个值,可以被后代组件注入

1. 类型定义

function provide<T>(key: InjectionKey<T> | string, value: T): void

2. 为 provide() 标注类型

为 provide() 标注类型, Vue 提供了一个 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,可以用来在提供者和消费者之间同步注入值的类型

import type { InjectionKey } from 'vue'
 
// 建议声明 key (name) 放到公共的文件中
// 这样就可以在 inject 的时候直接导入使用
const name = Symbol() as InjectionKey<string>
 
provide(name, '前端开发爱好者') // 若提供的是非字符串值会导致错误

以上方式是通过定义 key 的类型来标注类型的,还有一种方式直接 key 采用字符串的形式添加

provide('name', '前端开发爱好者')

八、inject()

inject()注入一个由祖先组件或整个应用供给的值

1. 类型定义

// 没有默认值
function inject<T>(key: InjectionKey<T> | string): T | undefined
 
// 带有默认值
function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
 
// 使用工厂函数
function inject<T>(
  key: InjectionKey<T> | string,
  defaultValue: () => T,
  treatDefaultAsFactory: true
): T

2. 为 inject() 标注类型

provide() 的 key 的类型是声明式提供的话(provide()类型标注的第一种形式)

inject() 可以直接导入声明的 key 来获取父级组件提供的值

// 由外部导入
const name = Symbol() as InjectionKey<string>
 
const injectName = inject(name)

如果 provide() 的 key 直接使用的字符串形式添加的, 需要通过泛型参数声明

const injectName = inject<string>('name')

九、模板 ref

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

<img ref="el" class="logo" :src="Logo" alt="" />
 
const el = ref<HTMLImageElement | null>(null)

十、组件 ref

有时,你可能需要为一个子组件添加一个模板 ref,以便调用它公开的方法

<!-- Child.vue -->
<script setup lang="ts">
const handleLog = () => console.log('前端开发爱好者')
 
defineExpose({
  open
})
</script>

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

<!-- parent.vue -->
<script setup lang="ts">
import Child from './Child.vue'
 
// 为子组件 ref 声明类型
const child = ref<InstanceType<typeof Child> | null>(null)
 
// 调用子组件中的方法
const getChildHandleLog = () => {
  child.value?.handleLog()
}
</script>

十二、事件处理器

原生的 DOM 事件标注类型

<template>
  <input type="text" @change="handleChange" />
</template>
 
<script setup lang="ts">
function handleChange(event: Event) {
  console.log((event.target as HTMLInputElement).value)
}
</script>
  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用Vue 3的组合式APITypeScript进行文件上传,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了Vue 3和TypeScript。您可以使用以下命令进行安装: ``` npm install vue@next npm install typescript ``` 2. 创建一个Vue组件,用于处理文件上传的逻辑。您可以在组件中使用`ref`来保存文件对象,并使用`onInput`事件监听文件选择器的变化。 ```typescript <template> <input type="file" @change="handleFileUpload" /> </template> <script setup lang="ts"> import { ref } from 'vue'; const file = ref<File | null>(null); const handleFileUpload = (event: Event) => { const target = event.target as HTMLInputElement; if (target.files && target.files.length > 0) { file.value = target.files[0]; } else { file.value = null; } }; </script> ``` 3. 在您的组件中,您可以使用`FormData`对象来创建一个包含文件的表单数据,并使用`axios`或其他HTTP库将表单数据发送到服务器。 ```typescript <script setup lang="ts"> import { ref } from 'vue'; import axios from 'axios'; const file = ref<File | null>(null); const handleFileUpload = async (event: Event) => { const target = event.target as HTMLInputElement; if (target.files && target.files.length > 0) { file.value = target.files[0]; const formData = new FormData(); formData.append('file', file.value); try { const response = await axios.post('/upload', formData); console.log(response.data); } catch (error) { console.error(error); } } else { file.value = null; } }; </script> ``` 4. 在服务器端,您可以使用任何后端框架(如Express.js)来处理文件上传。根据您使用的框架,您需要编写相应的路由处理程序来接收文件并将其保存到服务器上的适当位置。 这就是使用Vue 3的组合式APITypeScript进行文件上传的基本步骤。请注意,这只是一个简单的示例,您可能需要根据您的具体需求进行适当的修改和调整。希望对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值