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>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容