TypeScript基本使用

一、给组件的props参数定义类型

1.运行时声明

运行时声明是在代码运行时才会确定参数的类型,在编译阶段不会进行类型检测。

1.1 运行时-简单类型声明
<script setup lang="ts">
const props = defineProps({
title: String,
size: {
  type: String,
  required: true,
  validate(val: string) {
    return ['mini', 'default', 'large'].includes(val)
  }
}
})

props.title // title?: string | undefine
props.size  // size: string
< /script>

这种声明方式基本和选项式api的声明方式一致。

1.2 运行时-复杂类型声明

对于运行时声明,有时候我们需要给一个props参数声明为一个自定义接口类型,这时需要借助vue内部提供的PropType工具类型进行类型断言:

<script setup lang="ts">
import type { IUser } from './types.ts'
import type { PropType } from 'vue'

const props = defineProps({
 data: {
   type: Object as PropType<IUser>,
   required: true
 }
})

props.data  // data: IUser
< /script>

2.基于类型的声明

基于类型的声明在编译保存代码编译阶段就能确定类型,获得更好的类型提示。通过泛型参数来定义props的类型比较常用,通过这种方式定义的类型看起来也更加直观。

<script setup lang="ts">
import type { IUser } from './types.ts'
const props = defineProps<{
  title?: string,
  size: 'mini' | 'default' | 'large',
  data: IUser
}>()

props.title // title?: string | undefine
props.size  // size: "default" | "mini" | "large"
props.data  // data: IUser
< /script>

以上我们通过泛型定义的参数和上面基于运行时声明参数是一样的,但是明显可以看出这样写简洁了许多。

3.withDefaults定义参数默认值

基于类型的声明在给参数赋默认值时,需要借助withDefaults 编译器宏来实现。

<script setup lang="ts">
import type { IUser } from './types.ts'
const props = withDefaults(defineProps<{
  title?: string,
  size: 'mini' | 'default' | 'large',
  data: IUser
}>(), {
  title: '标题',
  size: 'default',
  data: () => {
    return {name: '细狗', age: 18}
  }
})
< /script>

注意:引用数据类型data给默认值时需要通过一个构造方法进行返回,并且给默认值后,原来在定义类型时是必传参,也会自动转化为可选参。

4.父组件传入泛型声明

有时候我们不确定props的参数类型,希望父组件通过传入泛型的方式进行类型定义,这时候我们可以使用 <script> 标签上的 generic 属性声明泛型类型参数:

<script setup lang="ts" generic="T, U extends Object">
const props = defineProps<{
  title?: T,
  data: U
}>()

props.title // title?: T | undefined
props.data  // data: U extends Object
< /script>

这时,我们在父组件中传递参数时,就能够自动推导出参数对应的类型了:

<template>
  <Item :data="user" title="人"></Item>  <!-- data:IUser,title?: string | undefined -->
  <Item :data="dog" :title="0"></Item>  <!-- data:IDog,title?: number | undefined -->
</template>

<script setup lang="ts">
import Item from './Item.vue'
import { ref } from 'vue' 
import type { IUser, IDog } from './types.ts'

const user = ref<IUser>({name: '细狗', age: 18})
const dog = ref<IDog>({name: '舔狗',color: '白色'})
< /script>

二、给组件定义的emits事件标记类型

1.运行时声明emits

<script lang="ts" setup>
const emit = defineEmits(['change', 'confirm'])
emit  // emit: (event: "change" | "confirm", ...args: any[]) => void
< /script>

这种声明方式比较方便,但是无法给触发的事件参数定义类型。如有这个需求,我们可以通过对象字面量的方式解决这个问题。

// 基于选项
const emit = defineEmits({
  change: (id: number) => {
    // 返回 true 或 false
    // 表明验证通过或失败
    if(id !== 1) return false
    return true
  },
  confirm: (_value: string) => {
    //value前面加个_,表示方法内可以忽略使用
    return true
  }
})
// emit  // emit: ((event: "change", id: number) => void) & ((event: "confirm", value: string) => void)
emit('change', 2) // 参数不是1,发出警告[Vue warn]: Invalid event arguments: event validation failed for event "change".
emit('confirm', 'a')
< /script>

2.基于类型声明emits

使用这种方式可以方便的定义多个参数类型和事件返回值类型,也是目前来看比较常见的一种方式。

const emit = defineEmits<{
  // 无返回值
  (e: 'change', id: number, value: string): void
  (e: 'confirm', value: string): void
}>()

除此之外,vue3.3+,也新出了一种更简洁的语法,当你不关注事件返回值类型时,可以考虑这这种写法:

const emit = defineEmits<{
  change: [id: number, value: string]
  confirm: [value: string]
}>()

这和前面声明的emits事件是一样的,都是没有返回值。

三、给ref标记类型

1.使用泛型

// 默认值类型推导
const count = ref(0); // count: Ref<number>
// 和上面一个等价
const count = ref<number>(0); // count: Ref<number>
// 不提供默认值时,类型推导会得到一个包含undefined的联合类型
const count = ref<number>(); // count: Ref<number | undefined>

2.Ref工具类型

const count: Ref<number> = ref()  // 不能将类型“Ref<number | undefined>”分配给类型“Ref<number>”
// ref()方法返回值类型必须和count定义的类型一致才行
const count: Ref<number | undefined> = ref()

3.给reactive标注类型

interface IState {
  name: string
}

// state得到的类型推断为: {name: string}
const state = reactive({
  name: '细狗'
})

// 显式声明类型,等价于上面的类型推导
const state: IState = reactive({
  name: '细狗'
})

四、给computed标记类型

const amount = ref(10)
// 隐式推导返回值类型,doubleAmount: ComputedRef<number>
const doubleAmount = computed(() => amount.value * 2)
// 显示定义返回值类型
const doubleAmount = computed<number>(() => amount.value * 2)

五、给provide / inject 标注类型

/* 父组件 */
provide('name', 0)

/* 子组件 */
// name没有默认值
const myName = inject<string>('name') // name: string | undefined
// 给name提供默认值
const myName = inject<string>('name', '哈哈') // name: string
console.log(myName) // 0

我们上面再父组件中提供了一个number类型的值,但是子组件中定义要注入的是string类型的值,这样子是不会报错的!为了保证正确的类型,我们需要使用Vue提供了一个InjectionKey接口,它是一个继承自Symbol的泛型类型,可以用来在提供者和消费者之间同步注入值的类型:

我们先建一个constant.ts保存项目常量的文件,把key定义在里面,这样子就可以父组件和子组件同时引入这个key使用了:

/** constant.ts */
import type { InjectionKey  } from 'vue'
export const name = Symbol() as InjectionKey<string>

/** 父组件 */
import { name } from './constant'
// provide(name, 0) // 类型“number”的参数不能赋给类型“string”的参数。
provide(name, '奥特曼')

/** 子组件 */
import { name } from './constant'
const myName = inject<string>(name, '哈哈') // name: string
console.log(myName) // 奥特曼

六、ts如何设置:当前代码行位置不进行ts校验 (允许使用js)

1.如果只是希望忽略某个具体的错误或警告,可以使用 // @ts-ignore 注释,放在希望忽略的代码行上方。

onMounted(() => {
  // @ts-ignore
  let a = add(1, '2');
  console.log(a, 'a');
});
function add(a: number, b: number): number {
  return a + b; 
}

2.在需要关闭 TypeScript 类型检查的文件开头加上 // @ts-nocheck 注释。这个注释告诉 TypeScript 在当前文件或者注释后面的代码段不进行类型检查。例如:

// @ts-nocheck
function add(a: number, b: number): number {
  return a + b;
}
add('1', 1);

区别总结

作用范围:@ts-nocheck 影响整个文件或者指定范围内的所有代码;@ts-ignore 仅影响其后紧邻的一行代码。
使用方式:@ts-nocheck 放置在文件首行;@ts-ignore 放置在需要忽略的具体代码行前面。

七、ts如何定义组件模板引用标注类型

父组件:
<template>
  <div>
    <Model ref="AARef" />
    <div @click="aaaa">22</div>
  </div>
</template>
<script setup lang="ts">
import Model from './a.vue';
import {ref} from 'vue';
const AARef = ref<InstanceType<typeof Model>>();
//这是 TypeScript 中的一种类型操作。typeof Model 返回 Model 的类型,然后 InstanceType 获取这个类型的实例类型。换句话说,InstanceType<typeof Model> 表示 Model 类的实例的类型。
const aaaa = (): void => { 
  AARef.value?.bb();
};
< /script>
子组件:
<template>
  <div>
    <el-dialog v-model="dialogVisible" title="提示" width="30%">
      <span>这是一段信息</span>
    </el-dialog>
  </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const dialogVisible = ref<boolean>(false);
const bb = (): void => {
  dialogVisible.value = true;
};
defineExpose({ bb });
< /script>

八、ts如何为 dom 模板引用标注类型

<template>
  <div>
  <el-input ref="el" />
  </div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue';
const el = ref<HTMLInputElement | null>(null);
 // HTMLInputElement | null:表示 el 可以引用一个 HTMLInputElement 类型的对象,或者是 null。
onMounted(() => {
  el.value?.focus();
});
< /script>
  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值