前言

文章记录编写了ts中涉及的基础知识,包含常用类型、类、函数、泛型等内容。同时按照vue3官方文档结合TypeScript + setup做vue3相关类型标注的举例。


Ts基础知识:

一、常用类型

  • TypeScript 最常见的三种类型 string、number、boolean、null 、 undefined
let str: string = 'hello world'       // 字符串
let count: number = 100               // 数字
let id:string = 1                    // 字符串或数字
let flag: boolean = true              // 布尔
let a: null = null                    // null
let b: undefined = undefined          // undefined

在ts中不能为已知类型的变量赋值不同类型:

str = 100    // 该行报错:不能将类型"number"分配给类型"string"
  • 数组:数组类型标注有两种方法:类型[]Array<类型>
let arr: string[] = ['a','b','c']
let arr2: Array<string> = ['a', 'b', 'c']
  • 元组:一种 Array 类型,它确切地知道包含多少个元素,以及它在特定位置包含哪些类型(带 ? 的表示为可选属性)
let tuple: [string,number,number[],boolean?] = ['a',1,[1,2]]
tuple = ['a', 1, [1, 2],true]
  • 对象:要定义对象类型,我们只需列出其属性及其类型
const obj: {
    name: string,
    age: number,
} = {
    name: "LiHua",
    age: 18,
};
// 解构形参的类型标注
function fun({ name, age }: { name: string, age: number }) {
    console.log(`${name}-${age}`);
}
  • any & unknown:对于未知类型的类型标注
  • 当一个值的类型是 any 时,可以访问它的任何属性,将它分配给任何类型的值,或者几乎任何其他语法
    上的东西都合法的
  • unknown 类型代表任何值。这与 any 类型类似,但更安全,因为对未知 unknown 值做任何事情都是
    不合法的。(用户调用时需要对其进行类型断言或者类型保护)
let id: any = 1
id = 'a'
id = [123, 'a']
console.log(id.length);

let id2: unknown = [1,2]
console.log(id2.length);     //改行报错:对象的类型为 "unknown"。
  • 枚举类型:它允许描述一个值,该值可能是一组可能的命名常量之一
enum Status {
    LiHua,
    XiaoHong,
    XiaoMing,
}
console.log(Status.LiHua);    // 0
console.log(Status[1]);       // XiaoHong

或者

enum Status {
    LiHua = 1,
    XiaoHong,
    XiaoMing,
}
console.log(Status.LiHua);    // 1
console.log(Status[1]);       // LiHua 
  • 文字类型:除了一般类型 string 和 number ,我们可以在类型位置引用特定的字符串和数字。用来规范输入的数据是什么。
function api(url: string, method: 'GET' | 'POST') {
    // ...
}
api('https://123.com', 'GET');
api('https://123.com', 'PUT');    // 报错:类型“"PUT"”的参数不能赋给类型“"GET" | "POST"”的参数。
  • never 类型意义主要有两种:
  • 1、表示该函数永远无法返回一个值
  • 2、做穷尽性检查,判断可能的情况是否已经罗列完毕

场景一:

function fail(msg:string):never {
    throw Error(msg)
}

场景二:

function request(method: 'get' | 'post') {
    switch (method) {
        case "get":
            return 'get...';
        case "post":
            return 'post...';
        default:
            const _exhaustiveCheck: never = method;
            return _exhaustiveCheck;
    }
}

当 method 增加一个值时:

function request(method: 'get' | 'post' | 'put') {
    switch (method) {
        case "get":
            return 'get...';
        case "post":
            return 'post...';
        default:
            const _exhaustiveCheck: never = method;    // 报错:不能将类型“string”分配给类型“never” ,因为 put 的情况没有列举
            return _exhaustiveCheck;
    }
}

二、类型别名与接口

类型别名和接口方便我们封装编写对象类型和联合类型,以便可以多次使用

  • 类型别名关键字: type
// 联合类型
type ID = string|number
let id:ID = 1
id = '1'
// 对象类型
type Student = {
    name:string;
    age:number;
}
let LiHua:Student = {
    name:'LiHua';
    age:18;
}
// 函数类型
type Fun = (value:'string')=>number
const geString:Fun = (value)=>{
    return value.length
}
  • 接口关键字:interface
interface Teacher {
    name: string;
    age: number;
    say(msg: string): string;
}
const LiHe: Teacher = {
    name: 'LiHe',
    age: 25,
    say(msg) {
        return `老师格言:${msg}`
    }
}

三、类型保护

我们认为一个变量可能有两种或两种以上的类型时,即称为联合类型:

interface Student {
    name: string;
    study:()=>{};
}
interface Teacher {
    name:string;
    teach: () => {};
}
function handle(people:Student|Teacher) {

}

此时由于我们未知people形参的类型,所以不能直接给该形参设置方法调用:

function handle(people:Student|Teacher) {
    people.study()    
    // 报错:类型“Student | Teacher”上不存在属性“study”。类型“Teacher”上不存在属性“study”。
}

所以此时我们就需要设置类型保护,类型保护主要有以下四种方法:

1. 类型断言

  • 语法:变量 as 类型
function handle(people: Student | Teacher, flag: 1 | 2) {
    if (flag === 1) {
        (people as Student).study()
    } else {
        (people as Teacher).teach()
    }
}

2. in 关键字

  • 语法:属性 in 变量
function handle(people: Student | Teacher) {
    if('study' in people) {
        people.study()
    } else {
        people.teach()
    }
}

3. typeof 关键字

  • 语法:typeof 变量 === “类型”
function operation(x: number | string, y: number | string) {
    if (typeof x === "string" || typeof y === "string") {
        return `${x}${y}`;
    }
    return x + y;
}

4. instanceof 关键字

  • 语法:变量 instanceof 类型
  • 注:该方法仅适用于对对象进行类型保护
class Student {
    name: string;
    study: () => {};
}
class Teacher {
    name: string;
    teach: () => {};
}
function handle(people: Student | Teacher) {
    if(people instanceof Student) {
        people.study()
    } else {
        people.teach()
    }
}

5. 配置判断函数

  • 1、设置判断函数,返回值类型为 “形参 is 类型”
  • 2、在使用时做分支判断
const isString = (val: any): val is string => typeof val === 'string';

const isArray = (val: any):val is Array<any> => Array.isArray(val);

function fun(value: number | []) {
    if(isArray(value)) {
        return value.length
    } else {
        return value
    }
}

四、泛型

泛型是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型,在未确定时泛型可以代表任意类型。

1.泛型类型

  • 语法:调用时使用 “<任意名称>” 定义泛型;调用时使用 “<类型>” 规范类型

例如:

function handle<T>(x: T, y: T): T {
    if (x === y) {
        return x
    } {
        return y
    }
}
handle<number>(1, 1)
handle<boolean>(true, false)
function handle<T>(arr: T[]): T {
    return arr[0]
}
handle<number>([1,2,3])
  • 多个泛型的使用:
function handle<T1, T2>(x: T1, y: T2) {
    return `${x}.${y}`
}
handle<number,string>(1,'第一项内容')

2.泛型约束

当我们知道一个泛型类型一定具有一个 “length” 属性且想调用该属性时是无法直接调用的,我们需要对已定义的泛型进行约束,例如:

function handle<T>(value:T) {
    return value.length
    // 报错:类型“T”上不存在属性“length”。
}

我们需要修改为:

function handle<T extends { length: number }>(value: T) {
    return value.length
}
handle<number[]>([1,2])   // 打印:2

========================

vue3+ts的基础使用:

一、常用标注

1. 响应式数据

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

// ref
// 可通过 Ref 或 调用ref时传入一个泛型参数
type code = number | string
let ts_ref1 = ref<string>('字符类型')
let ts_ref2: Ref<number[]> = ref([1, 2])
let ts_ref3 = ref<code>(1)
ts_ref3.value = '1'

// reactive
// 显性的给变量进行标注
interface student {
    name: string,
    age?: number,
    [orders: string]: any
}
const ts_reactive:student = reactive({
    id: 1,
    name:'小明',
    age:12,
})

// computed
// 调用computed时传入一个泛型参数
let data = ref<number>(1)
const ts_computed = computed<number>(()=>data.value*10)
</script>

2. 模板引用标注(获取dom)

<script setup lang="ts">
// 获取dom
const title = ref<HTMLElement|null>()
const handleClick = (event:Event): void=>{
    console.log("event=>", event);
    console.log("dom=>",title.value);
}
</script>
<template>
    <div class="dataDefinition">
        <div class="moduel">
            <h3 ref="title">function-ts:事件标注和dom获取:</h3>
            <button @click="handleClick">打印event和标题dom</button>
        </div>
    </div>
</template>

二、组件通信

1. props 标注类型

  • 父组件:
<script setup lang="ts">
import { ref} from "vue";
import student from "./components/student.vue";

let msg = ref<string>('父组件向子组件的通信数据...')
</script>
<template>
    <div class="communication">
        <div class="moduel">
            <h3>子组件相关:</h3>
            <student :msg="msg"></student>
        </div>
    </div>
</template>
  • 子组件( 使用类型声明的方式,便于 “编辑器报错和语法提示”):
<script setup lang="ts">
const props = withDefaults(defineProps<{
    msg: string,
    id?:number|string    // 非必传参数
}>(),{
	// 设置默认值
    msg:'暂无数据'
})
</script>
<template>
    <div class="student">
        {{ props.id }}、{{ props.msg }}
    </div>
</template>

效果:
在这里插入图片描述

2. emits 标注类型

  • 父组件:
<template>
    <div class="communication">
        <div class="moduel">
            <h3>子组件相关:</h3>
            <student @get-data="getdata"></student>
        </div>
    </div>
</template>
<script setup lang="ts">
const getdata = (value:string)=>{
    console.log(value);
}
</script>
  • 子组件:
<template>
    <button @click="getData">调用父亲getData方法,打印数据</button>
</template>

<script setup lang="ts">
const emits = defineEmits<{
    (e:'getData',value:string):void
}>()
const getData = ()=>{
    emits('getData','子组件向父组件的通信数据')
}
</script>

效果:
在这里插入图片描述

三、类型导入

  • 使用 “import type” 进行类型导入
  • “import type” 是用来协助进行类型检查和声明的,在运行时是完全不存在的。

如:

import type { Ref } from 'vue'

提示:文章到此结束,文章仅为个人学习记录,若有不足还请大家指出。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐