某次关于Vue和TS的分享

184 阅读8分钟

TypeScript

1.TS是什么

TypeScript 是 JavaScript 的一个超集,主要提供了类型系统对 ES6+ 的支持

本质上来讲 ts是在js的基础上添加了可选的静态类型和基于类的面向对象编程

2.TS特性

TypeScript 主要有 3 大特点:

  • 始于JavaScript,归于JavaScript

TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并且可以运行在任何浏览器上、Node.js 环境中和任何支持 ECMAScript 3(或更高版本)的JavaScript 引擎中。

  • 强大的类型系统

类型系统允许 JavaScript 开发者在开发 JavaScript 应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构。可以友好的在编辑器中提示错误, 编译阶段就能检查出大部分错误

  • 先进的 JavaScript

TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来自 2015 年的 ECMAScript 和未来的提案中的特性,以帮助建立健壮的组件。

3.JavaScript与TypeScript区别

3.1类型绑定

JavaScript是动态绑定类型, 只有运行程序才能知道类型, 在程序运行之前JavaScript对类型一无所知

TypeScript是在程序运行之前就会知道当前变量是什么类型。如果该变量并未定义类型, TypeScript会自动类型推导出来(但是ts中函数是不会自动类型推导的) 。如下:

image-20230313143902796

此时变量str的类型被推断为字符串类型

image-20230313144030226

3.2 类型转换

JavaScript中存在隐式转换, 此时会将Boolean类型的true转变成number类型 再与前面的1相加成2

const a = 1 + true
console.log(a) // 输出结果为 2

TypeScript中, 如上的代码会直接报错, 提示number类型不能与Boolean类型进行运算

image-20230313145632633

3.3 类型检查时间

JavaScript只有在程序运行中才能类型检查,类型也会存在隐式转换

TypeScript在编译时就会被类型检查, 如果与预期类型不符合就会在编辑器报错

Vue3

​ 首先Vue本身就是用 TypeScript 编写的,并对 TypeScript 提供了支持。所有的 Vue 官方库都自带了类型声明文件,开箱即用

可以更好的逻辑复用与代码组织

​ 在使用方面,Vue3从选项式Api转变为组合式Api,允许我们按功能组织数据和方法。打破了data(){}、methods:{}等固定结构的束缚,

​ 1.随着功能的增长,复杂组件的代码变得越来越难以阅读和理解。这种情况在开发人员阅读他人编写的代码时尤为常见。根本原因是 Vue 现有的 API 迫使我们通过选项组织代码,但是有的时候通过逻辑关系组织代码更有意义

​ 2.目前缺少一种简洁且低成本的机制来提取和重用多个组件之间的逻辑

更好的类型推导

使用

JavaScript语言本身的缺陷----弱类型, 比如 在JavaScript语言中, 一个变量, 可以先后保存不同类型的数据

var a = 'abc'  //此时a是一个保存字符串数据的变量
a = 2  // 给a重新赋值, 此时a是一个保存整数数据的变量

在大型项目的协作开发中, 强调的是严格和标准化. vue3和ts语言的结合, 实现了强类型检查 在编写程序的时候, 需要严格定义好要传递的数据类型和数据结构. 在编码的过程中, 开发者都要严格遵守数据类型和数据结构的规定.

TypeScript可以让我们在开发中避免一些类型或者一些不是我们预期希望的代码结果错误

​ eg: xxx is not defined 这种错误是JavaScript在运行中才会跑出的错误, 而TypeScript在使用过程中, 脚手架有自带的类型检查, 开发者在编码时, 一旦有类型使用错误, 就会报错

1.在单文件组件中的用法

​ 在单文件组件中使用TypeScript, 需要在<script>标签上加上lang="ts"的属性, 当lang="ts"存在时, 所有的模板内表达式都要接收严格的类型检查

<script lang="ts">
   
</script>

2.定义ts类型

ref

简单类型(可以使用泛型定义)
const value = ref<string | number>(0)

//2
let a = ref("a" as string);
复杂类型(可以定义interface等, 再写进泛型里)

​ 定义接口可以进行接口的复用

interface Person{
    name: string;
    age: number;
}

​ 在使用该interface时, 能够很好的给出对应属性名以及数据类型

image-20230313090513494

reactive(一般用来定义引用类型数据, 对象或者数组

我们以泛型去定义他们的类型 照样会有提示

image-20230313090832815

image-20230313092331335

defineProps

我们一般通过defineProps函数接收父组件传来的参数

<!-- 父组件代码 -->
<template>
  <HelloWorld msg="Welcome to Vue.js + TypeScript App" :age="age" />
</template>
<script setup lang="ts">
    import {ref} 'vue'
    const age = ref<number>(12)
</script>

<!-- 子组件代码 -->
<template>
  	<h1>{{ props.msg }}</h1>   
    <h2>{{ props.age }}</h2>
</template>
<script setup lang="ts">
    import {ref, defineProps} 'vue'
    //定义接收父组件传来的数据接口
    inteface Props {
        msg: string;
        age: number
    }
    
    const props = defineProps<Props>()
    
    //设置默认值
    const props = withDefaults(defineProps<Props>(), {
  		msg: "sfhjkd",
  		age: 12,
	});
</script>

子组件对应页面截图

image-20230313155729731

interface

​ 在项目中使用的较多就是接口---interface

interface People {
    name: string;
    age: number
}

const personOne: People = {
    name: 'one',
    age: 11
}

const personTwo: People = {
    name: 'two',
    age: 12
}

//使用interface定义了一个People的接口, 赋值给了personOne和personTwo两个变量, 实现了接口的复用

readonly修饰符

interface People {
    readonly name: string;
    age: number
}

const personOne = ref<People>({
  name: 'one',
  age: 11
})

image-20230313092354792

​ 在修改name属性时, 会提示以为name属性是一个只读属性, 所以没法修改

?可选修饰符

interface People {
    name: string;
    age: number;
    sex?: string
}

const personOne = ref<People>({
  name: 'one',
  age: 11
})

接口中 sex属性是可选属性, 被赋值的personOne中并未定义sex的属性, 是不会报错的

extends继承

interface People {
    name: string;
    age: number;
    sex?: string
}
interface Student extends People {
    idCard: string;
    className: string
}

image-20230313142724387

由图可以看出, 接口Student包含了自己本身定义的idCardclassName属性, 还有继承Peoplenameagesex属性

propName扩展

当接口定义好之后, 我们想在变量上自定义属性可以使用propName

interface human {
    name: string;
    age: number;
    [propName: string]: any  // 表示propName字段是string类型, 对应的value值可以是任意类型
}

const someOne: human = {
    name: 'lin',
    age: 12,
    address: 'dfhkafgkdf'  //此时不会报错
}

Type类型

用来声明类型别名

别名类型只能定义基础静态类型、对象静态类型、元组、联合类型(不可以定义interface类型)

也可以使用readonly修饰符以及 ?可选修饰符

type Types = string | number //基本数据类型 联合类型
type UserObj = {
    name:string, 
    age:string
} // 对象
type GetName = (name: string) => void  // 函数
type Student = UserObj & {idCard: string} // 交叉  -- 不能与其他type属性重合
type Data = [number,string] // 元组

//基本数据类型 联合类型
const str: Types = 'qaz'
const num: Types = 12

// 对象
const obj: userObj = {
    name: 'qaz',
    age: 12
}

// 函数
let func: GetName = (name: string) => {
    
}

//交叉类型 类似interface的扩展
const stu: Student = {
    name: 'wqq',
    age: 12,
    idCard: 'qswrfyiweh'
}

// 元组
const arr: Data = [1, '23']

与interface的区别与联系

interface可以多次定义,type不行

interface多次定义 会被视为合并,但是type多次定义的话会报同名错误

interface Student {
  name: string;
}

interface Student {
  age: string;
}
//不可以对已有属性重新定义别的类型
//此时Student实际{
	name: string;
	age: string
}
const stu: Student = {
  name: "wa",
  age: "12",
};

type多次定义

image-20230314095242766

type与interface交叉

interface Person {
    name: string;
    age: number
}

type Student = Person & {
    isCard: string
}
const stu: Student = {
    name: 'qaz',
    age: 12,
    idCard: 'ariehfk'
}

//interface可以extends继承 type 类型

type可以使用in关键字生成映射类型, 但是interface不行

type Types1 = "name" | "address";
type InType = {
  [key in Types1]: string;
};

const test: InType = {
  name: "12",
  address: "23",
};

type 可以使用typeof返回的值作为类型

let str1 = "animal";

type TypeStr = typeof str1;

let strType: TypeStr = "ad";

!修饰符 -- 非空类型断言

function func(value:string){
    console.log(value!.length)  // 在值后面加上 !修饰符表示确定value是一定有值的, 可以跳过ts在编译阶段对它的检测
}

func('zaq')

类型断言

类型断言可以手动指定一个值的类型

类似于其他语言里的类型转换, 不进行特殊的数据检查和结构,在编译时不是有影响

//第一种 尖括号语法
let str: any = 'qdafdsrfs'
let strLength: number = (<string>str).length 

//第二种 as 语法
// 正常
interface NameValue {
    name: string
}
interface AgeValue {
    age: number
}
function func(params: NameValue | AgeValue) {
    if ("name" in params) {
        const res = (params as AgeValue).name
        console.log(res)
    }
    if ("age" in params) {
        const res = (params as AgeValue).age
        console.log(res)
    }
}

func({age: 118})

联合类型

联合类型用 |表示

在定义某些变量时, 一开始没办法确定该变量类型, 可以使用联合类型, 如下代码, 变量满足其中的一个类型就可以

const flag : boolean | string = true

枚举Enum类型

枚举类型可以设置默认值, 如果不设置默认值对应值则为索引

enum className {
  math,
  english = "English",
  chinese = "Chinese",
}

console.log(className.math);   //  0
console.log(className.english);  // English
console.log(className["chinese"]); // Chinese

注意

如图image-20230313153616232

math没有设置默认值, 后面的 englishchinese设置了默认值,此时在后面给art不设置默认值, 此时代码不知道如何递增, 就会出现报错。

但是如果将枚举内的值设置为number类型,最后一个值会跟着上面一个数据进行递增, 不会报错

enum num {
    one,
    three = 3,
    four
}

console.log(num.four);  // 4
//枚举类型还可以通过value查询key值
console.log(num[3]);    // three

其他详细相关ts类型可见官网 www.tslang.cn/