vite除了支持基础阶段的纯TS环境之外,还支持 Vue + TS开发环境的快速创建, 命令如下:
$ npm create vite@latest vue-ts-pro -- --template vue-ts
说明:
开发阶段
好处:开发阶段的类型提示交给IDE做,保证vite的运行速度,打包阶段做’兜底类型校验’,确保类型无误
为ref标注类型之后,既可以在给ref对象的value赋值时校验数据类型,同时在使用value的时候可以获得代码提示
说明:本质上是给ref对象的value属性添加类型约束
ref 函数和 TS 的配合通常分为俩种情况,类型推导和泛型指定类型
标注ref函数类型,可以满足把下图所示的数据赋值给value属性
<script setup lang="ts">
import { ref } from 'vue'
type Item = {
id: string
name: string
age: number
}
const list = ref<Item[]>([])
list.value = [
{ id: '1', name: 'lxx', age: 19 },
{ id: '2', name: 'lss', age: 15 }
]
script>
<template>
<div v-for="item in list" :key="item.id">{{ item.name + ' : ' + item.age }}div>
template>
<style scoped>style>
计算属性通常由已知的响应式数据计算得到,所以依赖的数据类型一旦确定通过自动推导就可以知道计算属性的类型另外根据最佳实践,计算属性多数情况下是只读的,不做修改,所以配合TS一般只做代码提示
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
鼠标放在doubleCount可以得到推导结果
const doubleCount:ComputedRef<number>
需求:给ref函数标注类型,接收后端返回的对象列表,然后使用计算属性做过滤计算,计算得到单价大于500的商品
<script setup lang="ts">
import { computed, ref } from 'vue'
const data = [
{ id: '1001', name: '男鞋', price: 888 },
{ id: '1002', name: '女鞋', price: 232 },
{ id: '1003', name: '童鞋', price: 333 }
]
type Item = {
id: string
name: string
price: number
}
const list = ref<Item[]>(data)
const filterList = computed(() => list.value.filter(item => item.price > 500))
script>
<template>
{{ list }}
<hr />
{{ filterList }}
template>
<style scoped>style>
list的类型为:
const list: Ref<{
id: string;
name: string;
price: number;
}[]>
filterList推导出的类型为:
const filterList: ComputedRef<{
id: string;
name: string;
price: number;
}[]>
原生dom事件处理函数的参数默认会自动标注为any类型,没有任何类型提示,为了获得良好的类型提示,需要手动标注类型
如何给按钮元素button的点击事件函数标注类型?
<script setup lang="ts">
const clickHandler = (e: Event) => {
console.log(e.target as HTMLButtonElement)
}
script>
<template>
<button @click="clickHandler">clickbutton>
template>
<style scoped>style>
给模版引用标注类型,本质上是给ref对象的value属性添加了类型约束,约定value属性中存放的是特定类型的DOM对象,从而在使用的时候获得相应的代码提示
通过具体的DOM类型联合null做为泛型参数, 比如我们想获取一个input dom元素
尝试为模版引用标注类型获取一个a元素?
<script setup lang="ts">
import { onMounted, ref } from 'vue'
const aRef = ref<HTMLAnchorElement | null>(null)
onMounted(() => {
//aRef.value存放的数据在组件渲染完毕之前是null
//渲染完毕之后才是真实的dom
// 可选链.?
console.log(aRef.value?.href)
})
script>
<template>
<a href="#" ref="aRef">xxxa>
template>
<style scoped>style>
当对象的属性可能是 null 或 undefined 的时候,称之为“空值”,尝试访问空值身上的属性或者方法会发生类型错误
说明:inputRef变量在组件挂载完毕之前,value属性中存放的值为null,不是input dom对象,通不过类型校验
可选链 ?. 是一种访问嵌套对象属性的安全的方式, 可选链前面的值为 undefined 或者 null时,它会停止运算
非空断言(!)是指我们开发者明确知道当前的值一定不是null或者undefined,让TS通过类型校验
特别注意: 使用非空断言要格外小心,它没有实际的JS判断逻辑,只是通过了TS的类型校验,容易直接把空值出现在实际的执行环境里
给组件的Props标注类型有俩个作用,一个是确保传递的prop是类型安全的,另一个在组件内部使用的时候也会有类型提示
语法:通过defineProps宏函数对组件props进行类型标注
需求:按钮组件有俩个prop参数,color类型为string且为必填,size类型为string且为可选,怎么定义类型?
说明:按钮组件传递prop属性的时候必须满足color是必传项且类型为string, size为可选属性,类型为string
场景:Props中的可选参数通常除了指定类型之外还需要提供默认值,可以使用withDefaults宏函数来进行设置
需求:按钮组件的size属性的默认值设置为 middle
说明:如果用户传递了size属性,按照传递的数据来,如果没有传递,则size值为 ’middle’
给按钮组件添加一个btnType属性,类型为 ’success‘, ‘danger’ 或者 ’warning‘ 三选一, 默认值为 ’success‘
<script setup lang="ts">
import MyButton from './components/MyButton.vue'
script>
<template>
<MyButton btn-type="success">MyButton>
<MyButton>MyButton>
template>
<style scoped>style>
MyButton子组件
<script setup lang="ts">
type Props = {
btnType?: 'success' | 'danger' | 'warning'
}
const props = withDefaults(defineProps<Props>(), {
btnType: 'success'
})
console.log(props.btnType)
script>
<template>template>
<style scoped>style>
作用:可以约束事件名称并给出自动提示,确保不会拼写错误,同时约束传参类型,不会发生参数类型错误
语法:通过 defineEmits 宏函数进行类型标注
需求:子组件触发一个名称为 ’get-msg‘ 的事件,并且传递一个类型为string的参数
<script setup lang="ts">
import MyButton from './components/MyButton.vue'
const getMesageHandler = (e: string) => console.log(e)
script>
<template>
<MyButton @get-msg="getMesageHandler">MyButton>
template>
<style scoped>style>
<script setup lang="ts">
//定义事件类型Emits
type Emits = {
// 事件名称 事件参数类型
(e: 'get-msg', msg: string): void
}
//给emits标注类型
const emits = defineEmits<Emits>()
script>
<template>
<button @click="emits('get-msg', 'xxx')">按钮button>
template>
<style scoped>style>
Son组件再触发一个事件’get-list’, 传递参数类型为下图所示的数据类型
<script setup lang="ts">
import Son from './components/Son.vue'
type Item = {
id: number
name: string
}
const getListHandler = (e: Item[]) => e.forEach(item => console.log(item.id + ':' + item.name))
script>
<template>
<Son @get-list="getListHandler">Son>
template>
<style scoped>style>
<script setup lang="ts">
type Item = {
id: number
name: string
}
type Emits = { (e: 'get-list', msg: Item[]): void }
const emits = defineEmits<Emits>()
const clickHandler = () => {
const list = [
{ id: 1001, name: 'lxx' },
{ id: 1002, name: 'kobe' }
]
emits('get-list', list)
}
script>
<template>
<button @click="clickHandler">按钮button>
template>
<style scoped>style>
概念:在TS中以d.ts为后缀的文件就是类型声明文件,主要作用是为js模块提供类型信息支持,从而获得类型提示
说明:
场景:有些库本身并不是采用TS编写的,无法直接生成配套的d.ts文件,但是也想获得类型提示,此时需要 Definitely Typed 提供类型声明文件
DefinitelyTyped是一个TS类型定义的仓库,专门为JS编写的库可以提供类型声明,比如可以安装 @types/jquery 为jquery提供类型提示
TS为JS运行时可用的所有标准化内置API都提供了声明文件,这些文件既不需要编译生成,也不需要三方提供
说明:这里的lib.es5.d.ts以及lib.dom.d.ts都是内置的类型声明文件,为原生js和浏览器API提供类型提示
d.ts文件在项目中是可以进行自定义创建的,通常有俩种作用,第一个是共享TS类型(重要),第二种是给js文件提供类型(了解)
场景一:共享TS类型
说明:哪个业务组件需要用到类型导入即可,为了区分普通模块,可以加上type关键词
说明:通过declare关键词可以为js文件中的变量声明对应类型,这样js导出的模块在使用的时候也会获得类型提示
TS中有俩种文件类型,一种是.ts文件,一种是.d.ts文件
.ts文件
.d.ts文件
完整代码
https://gitee.com/lxxkobe/vue3-ts.git
之前业务开发我们用的是JavaScript,现在要加上TypeScript的类型,该如何把类型加进来呢?
核心思想:使用TS之后的业务开发思想是保持一致的,重要的是根据接口格式定义响应式数据的类型以及axios返回数据的类型即可
说明: 我们通过泛型参数传给request方法的ChannelRes类型约束了axios返回值res的data属性的类型
基础文章列表实现(固定频道id)
频道和文章列表联动实现(切换不同的频道id)