typescipt——基础积累

1.为组件的props标注类型

场景一:使用<script setup></script>

<script setup lang="ts">
const props = defineProps({
    
    
    foo:{
    
    type:String,required:true},
    bar:Number
})
props.foo //string
props.bar //number|undefined
</script>

也可以将props的类型移入一个单独的接口中

<script setup lang="ts">
interface Props{
    
    
    foo:string,
    bar?:number
}
const props = defineProps<Props>()
</script>

场景二:不使用<script setup></script>

import {
    
    defineComponent} from 'vue';
export default defineComponent({
    
    
    props:{
    
    
        message:String
    },
    setup(props){
    
    
        props.message //类型:string
    }
})

注意点:为了生成正确的运行时代码,传给defineProps()的泛型参数必须是以下之一:

1.一个类型字面量:

defineProps<{
    
    /*...*/}>()

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

interface Props{
    
    /*...*/}
defineProps<Props>()

3.接口或对象字面类型可以包含从其他文件导入的类型引用,但是,传递给defineProps的泛型参数本身不能是一个导入的类型:

import {
    
    Props} from './other-file'
//不支持
defineProps<Props>()

Props解构默认值

当使用基于类型的声明时,失去了对props定义默认值的能力,通过目前实验性的响应性语法糖来解决:

<script setup lang="ts">
interface Props{
    
    
    foo:string,
    bar?:number
}
//对defineProps()的响应性解构
//默认值会被编译为等价的运行时选项
const {
    
    foo,bar=100} = defineProps<Props>()
</script>

2.为组件的emits标注类型

场景一:使用<script setup>

<script setup lang="ts">
const emit = defineEmits(['change','update']);
//基于类型
const emit = defineEmits<{
    
    
    (e:'change',id:number):void
    (e:'update',value:string):void
}>()
</script>

场景二:不使用<script setup></script>

import {
    
    defineComponent} from 'vue';
export default defineComponent({
    
    
    emits:['change'],
    setup(props,{
     
     emit}){
    
    
        emit('change')
    }
})

3.ref()标注类型

import {
    
    ref} from 'vue';
import type {
    
    Ref} from 'vue';

//1.ref会根据初始化时的值推导其类型
//推导出的类型:Ref

const year = ref(2020)
//=>TS Error:Type string is not assignable to type number
year.value = '2020'

//2.指定一个更复杂的类型,可以通过使用Ref这个类型

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

//3.在调用ref()时传入一个泛型参数,来覆盖默认的推导行为:
//得到的类型:Ref<string|number>

const year = ref<string|number>('2020')
year.value = 2020

//4.如果你指定了一个泛型参数但没有给出初始值,那么最后得到的就将是一个包含undefined的联合类型
//推导得到的类型:Ref<number|undefined>

const n = ref<number>()

4.为reactive()标注类型

import {
    
    reactive} from 'vue';

//1.reactive()也会隐式的从它的参数中推导类型:
//推导得到的类型:{title:string}

const book = reactive({
    
    title:'vue3 指引'})

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

interface Book{
    
    
    title:string,
    year?:number
}
const book:Book = reactive({
    
    title:'vue3指引'})

5.为computed()标注类型

import {
    
    ref,computed} from 'vue';

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

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.通过泛型参数显式的指定类型

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

6.为事件处理函数标注类型

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

<script setup lang="ts">
function handleChange(event){
    
    
    //没有类型标注时 event 隐式的标注为any类型
    //这也会在tsconfig.json中配置了strict:true或noImplicitAny:true时报出一个TS错误
    console.log(event.target.value);
}
</script>
<template>
    <input type="text" @change="handleChange"/>
</template>
//因此,建议显式的为事件处理函数的参数标注类型,需要显式的强制转换event上的属性:
function handleChange(event:Event){
    
    
    console.log((event.target as HTMLInputElement).value)
}

7.为provide/inject标注类型

provide和inject通常会在不同的组件中运行,要正确的为注入的值标记类型
vue提供了一个injectionKey接口,它是一个继承自symbol的泛型类型
可以用来在提供者和消费者之间同步的注入值的类型:

import {
    
    provide,inject} from 'vue';
import type {
    
    InjectionKey} from 'vue';
const key = Symbol() as InjectionKey<string>
provide(key,'foo')//若提供的是非字符串值会导致错误
const foo = inject(key)//foo 的类型:string |undefined

//建议将注入key的类型放在一个单独的文件中,这样它就可以被多个组件导入
//当使用字符串注入key时,注入值的类型是unknown,需要通过泛型参数显式声明:

cont foo = inject<string>('foo')//类型:string|undefined

//注意注入的值仍然可以是:undefined,因为无法保证提供者一定会在运行时provide这个值
//当提供了一个默认值后,这个undefined类型就可以被转移

const foo = inject<string>('foo','bar')//类型:string

//如果你确定该值将始终被提供,则还可以强制转换该值

const foo = inject('foo') as string

8.为模板引用标注类型

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

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

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

<template>
    <input ref="el"/>
</template>

9.为组件模板引用标注类型

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

<!--MyModal.vue-->
<script setup lange="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>

//注意:如果你想在typescript 文件而不是在vue sfc中使用这种技巧,需要开启volar的takeover模式

猜你喜欢

转载自blog.csdn.net/yehaocheng520/article/details/131983622