• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Vue3项目使用TypeScript

武飞扬头像
程序员海军
帮助1

学新通

单文件用法

在单文件组件中使用 TypeScript,需要在

学新通

小结:

<script lang="ts">

</script>


<script setup lang="ts">

</script>

注意

当 script 中使用了 ts ,模板 template 在绑定表达式时也支持ts。
如果在表达式中不指名类型时,编译器会报警告提示。

学新通

正确写法
表达式指定类型
学新通

组合式API TS

Props 标注 类型

学新通

基于运行时声明

当使用

<script setup lang="ts">
  const props = defineProps({
    name: String,
    data:{
      type: Object,
      required: true
    }
  })
    </script>

基于类型声明

通过泛型来定义 Props

<script setup lang="ts">
interface MyProps {
    phone: string | number,
    name ?: string,
    age : number | string
    hobby: {
        type: string,
        required: true
    }
}


const props = defineProps<MyProps>()
</script>
语法规定

传递给 defineProps 的泛型参数必须是以下格式:

defineProps<{ /*... */ }>()     一个对象字面量

同一个文件中的一个接口或对象类型字面量的引用:

interface Props {/* ... */}

defineProps<Props>()

Props 默认值

当使用了 基于类型声明时,就失去了 默认值 能力。 Vue 提供了一个 Api 可以解决此问题, **withDefaults **编译器哄解决。
withDefaults 可以提供默认值的类型检查

先来复习一下 基于运行时怎么 声明默认值 Props

const props = defineProps({
    name: {
      type: String,
      default: () => '默认值'  
    },
    data:{
        type: Object,
        required: true
    }
})

基于运行时 Props 默认值写法:

interface MyProps {
    phone: string | number,
    name ?: string,
    age : number | string
    hobby: {
        type: string,
        required: true
    }
}

const props =  withDefaults(defineProps<MyProps>(),{
    name:'海军',
    phone: '123123123123'
})  

没有使用

当没有使用

import { defineComponent } from 'vue'

export default defineComponent({
  props: {
    message: String
  },
  setup(props) {
    props.message // <-- 类型:string
  }
})

注意

  1. 传递给 defineProps 的参数本身不能是一个导入类型, 只能是当前文件下的一个对象或者interface
因为 Vue 组件是单独编译的,编译器目前不会抓取导入的文件以分析源类型。我们计划在未来的版本中解决这个限制。

  1. 基于运行时声明 和 基于类型声明 不能混着用

Emits 类型标注

学新通

在 < script setup> 写法

在 < script setup> 中 , 给emit 函数 类型标注 可以通过两种形式来标注

  1. 运行时声明
  2. 类型声明

运行时声明写法

//运行时写法
const emit = defineEmits(['getData'])

  emit('getData', {
      code:200,
      msg: "传入数据成功",
      str:"我是子组件过来的数据"
  })

类型声明写法

const emit = defineEmits<{
    (e: 'getId', id: number): void
}>()


 emit('getId',2)

基于类型的声明使我们可以对所触发事件的类型进行更细粒度的控制。

在 defineComponent 中写法

defineComponent() 也可以根据 emits 选项推导暴露在 setup 上下文中的 emit 函数的类型:

import { defineComponent } from 'vue'

export default defineComponent({
  emits: ['change'],
  setup(props, { emit }) {
    emit('change') // <-- 类型检查 / 自动补全
  }
})

ref 标注类型

有时我们想给 ref 指定一个 复杂类型时, 可以通过 Ref 类型 声明 或者 调用 ref 时 传入一个泛型参数 来覆盖默认推倒行为。

Ref 声明

import type {Ref} from "vue"

const studentId: Ref< String | Number> = ref(231)

泛型声明

调用ref 时,传入一个泛型参数,来覆盖默认的推倒行为

const teacherId = ref<String | Number>('4')

注意

  • 如果泛型参数没有给定初始值,那么会得到一个 undefined 的联合类型

reactive 标注类型

通过 定义一个接口 来做类型约束

interface StudentInfoFormat {
    name: string,
    id: number,
    age: number,
    hobby ?: string
}




const info : StudentInfoFormat = reactive({name:'海军',id:2})

const getStudentInfo = (data : StudentInfoFormat) => {
    console.log(data)
}

getStudentInfo(info)
学新通

这样就有很好的类型提示。
上面定义来 一个 可选属性 hobby,在初始化时,没有传递 age属性, 下面提示了 缺少 age 。
学新通

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('')

泛型参数指定返回类型

若返回的参数不是指定的参数类型则会报错

computed<T>(() => {})
const num = computed<number>(() => {
    return 99 * 44
})

事件函数标注类型

在处理原生 DOM 事件时,应该为我们传递给事件处理函数的参数正确地标注类型。

 <input type="text" @change="change">
const change = (e : Event) => {
    
    console.log((e.target as HTMLInputElement).value)
}

当 参数 e 没有标注类型时, 它的类型为 any 。 如果在tsconfig.json 中配置了 “strict”: true 或 “noImplicitAny”: true 时报出一个 TS 错误。
我们可以显式强制转化 event 属性 , 让浏览器更好的知道类型。

Provide / inject 标注类型

在组件传值时,有时组件嵌套太深时,组件通信就变的麻烦起来了。 如果子子孙组件需要获取顶级组件状态时,那么它可以 通过 Vuex / Pinia / 事件总线 来通信,不过,不建议这样做。一般用 Vuex / Pinia 一般存储一些全局的状态时使用,这里用就小题大做了。 我们可以通过在顶级组件 Provide 提供需要的值,然后在它所嵌套的组件中注入需要的值即可,这样状态也好管理。

在Vue3 中,如果我们要给 提供的值 标注类型,可以借助这个 接口 来实 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,可以用来在提供者和消费者之间同步注入值的类型。

单独封装key

单独封装key 的好处,这样我们在别的组件也可以使用该key 做为类型标注。

//provideKey.ts

import { provide, inject } from 'vue'
import type { InjectionKey } from 'vue'


export  const key = Symbol() as InjectionKey<string>



组件中 Provide

在顶级组件中提供 key , 供下级组件使用key

import {key} from "../../common/provideKey"
import {provide} from "vue"

provide(key,'标注类型')

如果没有key 的value 类型不是指定的类型,则会报警告提示
学新通

下级组件 inject

下级组件注入 key

import { inject } from "vue"


const key = inject('token')

模板ref 标注类型

有时,我们需要通过原生DOM 做一些操作,就需要获取到原生DOM.
下面是 获取表单元素,进入该组件时,自动聚焦。

<el-input v-model="str" placeholder="" size="normal" clearable @change="" ref="formInputRef"></el-input>
const str = ref("测试")

const formInputRef = ref<HTMLInputElement | null>(null)


onMounted(() => {
    formInputRef.value?.focus()
})
   

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

获取子组件 类型

有时候,我们需要直接操作子组件来获取它的状态和方法。 在Vue2.x 中,我们可以直接在子组件中绑定ref,然后通过 this.$refs.绑定的ref 就可以使用了。
在 Vue 3中,我们也是如此。但是在组合式API 中,调用的时候,不用this了,通过 ref.value 来操作。

**想要给给子组件标注类型时: **
我们就需要先通过 typeof 来 获取组件的类型,然后通过TypeScript 内置的InstanceType 工具类型来获取其实例类型,就可以操作子组件了。

  <ts-component   ref="tsRef" ></ts-component>

一般不标准类型写法:

<script setup lang="ts">
  import TsComponent from '../TsComponent/index.vue'
	const tsRef = ref(null)


  tsRef.value?.alerTest('测试')    //调用子组件方法
</script>

标注类型写法:

<script setup lang="ts">
  import TsComponent from '../TsComponent/index.vue'

	const tsRef = ref<InstanceType<typeof TsComponent> | null>(null)

  tsRef.value?.alerTest('测试')    //调用子组件方法
</script>

选项式API TS

在Vue3 中 选项式 API 想要做类型推倒,得使用 defineComponent() 来包装组件。

Props 标注类型

需要使用 defineComponent() 包装组件包裹起来,

简单类型

只做简单类型推倒

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
    props:{
      code:{
        type:Number,
        default:22,
        required:true,
      },
      content:{
        type:String,
        default: () => "测试"
      }  
    },

})

</script>
学新通

复杂类型

有时,我们需要对Props 的属性要求是复杂类型或者多层级进行类型要求,按一般的写法是实现不了的,可以通过PropType 这个工具类型来标记更复杂的 props 类型

import { defineComponent } from 'vue'
import type { PropType } from 'vue'

interface InfoFormat {
    code: {
        type: number,
        required: true
    }
    msg:{
        type: string
    }
}


export default defineComponent({
    props:{ 
      info: {
        type:  Object as PropType<InfoFormat>,
      }
    },
})

学新通
注意

如果你的 TypeScript 版本低于 4.7,在使用函数作为 prop 的 validator 和 default 选项值时需要格外小心——确保使用箭头函数

emits 标注类型

:::info
可以给 emits 选项提供一个对象来声明组件所触发的事件,以及这些事件所期望的参数类型。试图触发未声明的事件会抛出一个类型错误
:::

事件加参数类型验证

    emits:{
        getData(ctx:{name:string,age:number}) {
            // 内部可以加 一些验证
            // return
            return 
        }
    },


//触发事件
this.$emit('getData',{name:'海军',age:22})

如果我们给emit 事件加了参数类型验证,当触发事件时,没有传递参数或者参数类型错误 都会警告提示。
学新通

计算属性 标注类型

计算属性会自动根据其返回值来推导其类型。
在某些场景,我们需要显示的标记出 计算属性的类型。因为在某些 TypeScript 因循环引用而无法推导类型的情况下,可能必须进行显式的类型标注。

  computed:{
      filterData(): Array<{code:number,msg:string}> {
          if(this.arrList.length == 0) {
              return []
          } else{
              return this.arrList.filter(i => i.code == 200)
          }
      }
  },

事件处理函数 标注类型

import { defineComponent } from 'vue'

export default defineComponent({
  methods: {
    handleChange(event: Event) {
      console.log((event.target as HTMLInputElement).value)
    }
  }
})

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhchejec
系列文章
更多 icon
同类精品
更多 icon
继续加载