当前位置: 首页>前端>正文

vue3+Ts 小结

vue3+Ts 指南

一、Ts的基本类型注解

String类型标注

let name:string='Vue3'

Number类型标注

let test1:number=10      //十进制
let test2:number=0b1010  //二进制
let test3:number=0o12    //八进制
let test4:number=0xa     //十六进制

Boolean类型标注

let isShow:boolean=false

Array类型标注

let list1:number[]=[1,2,3]
let list2:Array<string>=['1', '2', '3']

let list3:[string,number]  //元组类型
    list3=['hello',1] //正确
    list3=[1,'hello'] //错误

Object类型标注

  • object类型中,对象内部定义的值是不受类型约束的
let obj : object = {
    name : '小明',
    age : 18
}
function getObj (obj:object) : object {
    console.log(obj);
    return {
        name : ‘张’ + obj.name,
        age : obj.name + 30
    }
}

null和undefined类型标注

  • null和undefined,默认情况下它们是所有类型的子类型,可以赋值给任意类型
  • 严格模式下 null和undefined 除自身和void之外不能赋值给其他类型
let demo1:undefined=undefined
let demo2:null=null
let demo3:string | null = 'demo3'
    demo3 = null

any类型

  • 表示可以声明为任意类型
let any1:any=4
    any1=='哈哈哈
    any1=false
let anyList:any[]=[1,true,'free']

void类型

  • void类型与any类型相反,它表示没有任何类型
  • 一般用来说明函数的返回值不能是undefined和null之外的值
function fn():void{
 consoloe.log('void')
 //return undefined
 //return null
}

接口

  • 接口是对象的状态(属性)和行为(方法)的抽象(描述)
interface IPerson{
 readonly id:number, // 只读属性
 name:string,
 age:number,
 sex?:string        //可选属性
}

type

  • type作用就是给类型起一个新名字,支持基本类型、联合类型、元祖或者自定义的类型
type customNumber = number; //基本类型
let num: customNumber = 10;

type userOjb = {name:string} // 对象
let user1: userObj = {name: '张小明'}

type data = [number,string] // 元组
let list: data = [1, '测试']

// 联合类型
interface Obj1 {
  name: string;
}
interface Obj2 {
  age: number
}
type AllObj = Obj1 | Obj2  // 联合类型
// type AllObj = Obj1 & Obj2  // 交叉类型
// type ObjList = [Obj1, Obj2]  // 元组类型
let instanceObj: AllObj = { name: "aa", age: 1 };

// type与接口的差别
// 区别1: 定义类型范围不同
//        interface 只能定义对象类型或接口当名字的函数类型
//        type 可以定义任何类型,包括基础类型、联合类型、交叉类型、元组
// 区别2: 合并声明
//        定义两个相同名称的接口会合并声明
//        定义两个同名的type会出现编译错误
// 区别3: 拓展性
//        interface接口可以使用extends和implements进行拓展

泛型

  • 在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型
// 函数中使用泛型
function test <T> (arg:T):T{
  console.log(arg);
  return arg;
}
test<number>(111);// 返回值是number类型的 111
test<string | boolean>('hahaha')//返回值是string类型的 hahaha
test<string | boolean>(true);//返回值是布尔类型的 true

//接口泛型
interface ibaseCRUD<T>{
  data:T[]
  add:(t:T)=>void
  getById:(id:number)=>T
}

// 泛型约束
interface Lengthwise{
  length:number
}
function test<T extends Lengthwise>(x:T):number{
  console.log(x.length)
  return x.length
}
test('123')      //正确
test([1, 2, 3])  //正确
test(123)        //错误


//泛型工具类型
// 1. Partial
// partial<T>的作用就是将某个类型中的属性全部变为可选项?
interface Person {
  name: string;
  age: number;
}
let personqwe: Partial<Person> = { name: "11" };
// 2. Record
// Record<K, T>是将K中所有的属性转换为T类型
type keys = 'A' | 'B' | 'C'
const result: Record<keys, number> = {
  A: 1,
  B: 2,
  C: 3
}
// 3. Pick
// Pick<T, K>的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型
interface Todo {
  title:string,
  desc:string,
  time:string
}
type TodoPreview = Pick<Todo, 'title'|'time'>;
const todo: TodoPreview ={
  title:'吃饭',
  time:'明天'
}

联合类型

  • 联合类型表示取值可以为多种类型中的一种
let value: string | number;
    value = 1
    value = "a"

// 接口联合类型
interface Obj1 {
  name: string;
}
interface Obj2 {
  age: number
}
type AllObj = Obj1 | Obj2  // 联合类型
let instanceObj: AllObj = { name: "aa", age: 1 };

交叉类型

  • 具有所联合类型的所有成员
interface People {
  age: number;
  height: number;
}
interface Man {
  sex: string;
}
const user: People & Man = { age: 12, height: 170, sex: "男" };

二、Vue3中使用Ts

ref标注类型

<script lang="ts" setup>
import { ref } from 'vue'
import type { Ref } from 'vue'

// 泛型参数类型标注
const age = ref<number>(20); 或者 const age = ref<number | string>(20);

// 接口标注类型
interface book {
    name: string
    price: number
}
const book = ref<book>({
    name: '张小明',
    age: 48
})

// 直接给声明的变量添加类型
const name: Ref<string> = ref('张三');
// 为什么不是  const name: string = ref('张三');
// Vue3代理对象用的是Proxy ,Proxy的代理目标必须是引用类型, 所以增加了Ref的类型描述

const sex = ref('男') as Ref<string>;
// 推荐使用前两种方式,前两种方式都是以泛型的形式来标注类型的
// 拓展类型Ref还需要额外的引入
</script>

reactive 标注类型

<script lang="ts" setup>
import { reactive } from 'vue'
interface person {
    name: string;
    age: number;
    sex: string;
}
// 直接给声明的变量添加标注类型
const father: person = reactive({
    name: '张三',
    age: 30,
    sex: '男'
})
// 通过泛型参数添加标注类型
const son = reactive<person>({
    name: '小张',
    age: 23,
    sex: '男'
})
// 注意:官方并不推荐使用reactive泛型参数,因为泛型的参数类型与深层次ref解包的返回值不同, 推荐直接给声明的变量添加类型
<script>

computed 标注类型

<script lang="ts" setup>
import { ref, computed } from 'vue'
import type { Ref, ComputedRef } from 'vue'

const count = ref<number>(10);
// 或者
// const count: Ref<number> = ref(10);

// 通过泛型参数添加标注类型
const doubleCount = computed<number>((): number => count.value * 2)

// 直接给声明的变量添加类型
const trebleCount : ComputedRef<number> = computed((): number => count.value * 3)

const fourfoldCount = computed((): number => count.value * 4) as ComputedRef<number>

<script>

defineProps

  • 组件接收的值
<script lang="ts" setup>
import { defineProps } from 'vue'
// 常规写法
const props1 = defineProps({
    name1: String,
    name2: {
        type: String,
        required: true
    },
    list: {
        type: Array as () => Array<string>,
        required: true,
        default: () => ([])
    }
})

// 通过泛型参数来定义 props 的类型
interface Props2 {
  name1?: string;
  name2: string;
  list: string[]; // 或者Array<string>
}
const props2 = defineProps<Props2>()

// 泛型参数props定义默认值
interface Props3 {
  name1?: string;
  name2: string;
  list: (string | number)[]; // 或者Array<string | number>
}
const props3 = withDefaults(defineProps<Props3>(), {
  name1: "name1111",
  name2: "name2222",
  list: () => ["1", "2", 3],
});
<script>

defineEmits

  • 向外事件传递
<script lang="ts" setup>
import { ref, defineEmits } from 'vue'
interface Emits {
  (event: "getMsg", name: string): void;
}
let name = ref<string>("张小明");
const emit = defineEmits<Emits>();
const transmit = (): void => {
  emit("getMsg", name.value);
};
<script>

defineExpose

  • 向外暴露属性
  • setup语法糖 默认组件是关闭的, 无法通过组件实例获取组件的属性和方法
// 子组件--child.vue
<script lang="ts" setup>
import { ref, defineExpose } from 'vue'

let name = ref<string>("张小明");

defineExpose({name})

<script>

// 父组件
<template>
  <div class="home">
    <Child ref="childElInstance" @getMsg="testEmite"></Child>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted } from 'vue'
import Child from "./Child.vue";

// 获取元素或组件实例
const childElInstance = ref<HTMLImageElement | null>(null);  // 或者 const childElInstance = ref<any>(null); 不建议
// 获取组件实例
//const childElInstance = ref<InstanceType<typeof About> | null>(null);

onMounted(() => {
  console.log(childElInstance?.value?.name);
});

<script>

provide

  • provide提供一个值,可以被后代组件注入
  • 接受两个参数,第一个参数称为注入名,也就是key,可以是字符串或者Symbol。第二个参数是值,要传递的数据,任意类型的数据
<script lang="ts" setup>
import { provide } from 'vue';
import type { InjectionKey } from 'vue'

// key为string类型
provide('data', '这是暴露出来的数据');

// key为Symbol类型
// Vue提供了一个InjectionKey接口 用于类型标注
// ES6引入了一种新的原始数据类型Symbol,表示独一无二的值, 可以作为对象的属性名, 避免属性名冲突
const data = Symbol() as InjectionKey<string>; // 这里的声明放到公共的文件中
provide(data, '这是暴露出来的数据');

<script>

inject

  • inject注入一个由祖先组件或整个应用供给的值
  • 有两个参数,第一个参数称为注入名,也就是key, 第二个参数是指定默认值
<script lang="ts" setup>
import { inject } from 'vue'
import { data } from '------'  // 这里引入公共文件申明的Symbol类型数据
// key为string类型
const injectName1 = inject<string>('data')

// key为Symbol类型
const injectName2 = inject(data)
<script>

https://www.xamrdz.com/web/2en1848569.html

相关文章: