vue3中使用TypeScript
首先,尤雨溪说 Vue3:语法不变、TS 支持很好,之前我已经讲解过Vue3,没有看过的朋友可以去看一下,那我们先了解一下什么是TypeScript
了解TypeScript
TypeScript(简称TS),是JavaScript的超集(JS有的TS都有,JS没有的TS也有)TypeScript = type + JavaScript(为JS添加了类型系统)
//TS有明确的类型区分
let name: string = "张三";
//JS没有类型区分
let name = "张三"
TypeScript起源于使用JavaScript开发的大型项目 。由于JavaScript语言本身的局限性,难以胜任和维护大型项目开发。因此微软开发了TypeScript ,使得其能够胜任开发大型项目。
TypeScript优势
JS存在"先天缺陷",大部分错误都是类型错误(Uncaught TypeError)
类型化思维方式,使开发更加严谨,提前发现错误。- 类型系统提高了代码可读性,
便于维护和重构代码。 - 补充了
接口,枚举等JS缺失功能 - Vue3源码使用TS,Angular默认支持TS,React完美配合TS
TypeScript规则
在ts中,为了使代码更加规范,便于维护,增加了类型校验,提供了许多的类型校验,布尔类型(boolean),数字类型(number),字符串类型(string),数组类型(array),元组类型(tuple),枚举类型(enum),任意类型(any),null和undefined,void类型,never类型
大致用法如下。
//布尔类型(boolean)
let flag:boolean=false;
flag=true
//数字类型(number)
let num:number=123
//字符串类型(string)
let str:string="好家伙"
//数组类型(array)
//第一种定义数组方式
let arr:number[]=[1,2,3]
let arr:string[]=['张三','李四','王五']
//定义联合类型数组,与上面相同
let arr:(number | string)[]
//如果你不太清楚定义的是数字还是字符串or布尔类型,你可以用any定义(我愿称他为yyds!!!)
let arr:any[]=['张三',15,'李四',18,{name:'李四',age:20}]
//第二种定义数组方式(使用泛型)
let arr2:Array<string> = ["张三","李四"]
//如果要在数组里面写对象,并且要限制内容格式
const arr:{name:string,age:number}[]=[
{name:'张三',age:18},
{name:'李四',age:20}
]
//如果这个格式要在很多地方用到,那么可以用类型别名 type
type Lady={name:string,age:number}
const arr:Lady[]=[
{name:'张三',age:18},
{name:'李四',age:20}
]
//也可以用类的方式 class
class Lady {name:string,age:number}
const arr:Lady[]=[
{name:'张三',age:18};
{name:'李四',age:20}
]
//元组类型(tuple)属于数组的一种,可以指定数组里值的类型
//赋值的类型、位置、个数需要和定义(生明)的类型、位置、个数一致。有一说一,没必要,我反正没用过。
let arr:[number,string]=[123,"张三"]
//枚举类型(enum)主要是用来定义标识符
//默认情况下,One 的初始值为 0,其余的成员会从 1 开始自动增长。
enum Status {
One,
Two,
Three
}
可以自己定义初始值,或者自己赋值
enum Status {
One=1,
Two,
Three
}
//任意类型(any)
//任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的顶级类型(也被称作全局超级类型)。
//如果你确实不知道是什么类型,那么可以写any,但是不要通篇写any,那么你写ts的意义是什么呢
let a:any=120
a='123'
//void类型
//表示没有任何类型,一般用于定义方法,方法没有返回值
function fn():void{
console.log(123)
}
//要是有返回值,返回的是什么就写什么
function fn():number{
return 123
}
//never类型
//never类型表示的是那些永不存在的值的类型。
//`never`类型同null和undefined一样,也是任何类型的子类型,也可以赋值给任何类型。
//但是没有类型是never的子类型或可以赋值给never类型(除了never本身之外),即使any也不可以赋值给never
如果前期定义了类型是什么,后期就赋值相对应类型,如果赋值不是相对应类型,那么会报错
接口:什么是接口,接口也是一种类型, 也是用来约束使用者的,他的作用是进一步定义对象内的各种属性。
其他补充
- 接口:接口是一种规范的定义,它定义了行为和动作的规范
//接口,比如说定义的东西用过很多次,那就可以用到接口,?是代表不确定有没有这个参数(可选值)
interface Man {
name:string;
age:number;
job ?:string;
}
const man={name:'李四',age:20}
const fn=(man:Man)=>{
if(man.name){
console.log(man.name)
}else if(man.age){
console.log(man.age)
}else if(man.job){
console.log(man.job)
}
}
//如果你还想写任意东西,不被限制,那么
interface Man {
[propname:string]:any
}
//也可以定义方法,下面定义的是返回值为字符串
interface Man {
say():string
}
//也可以升级
//这样的话Mans必须要遵守Man的规则,并且可以添加定义的东西
interface Mans extends Man{
fullname:string
}
- 泛型:可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。泛型可以帮助我们避免重复代码以及对不特定数据类型的支持(类型校验) 比如说这样,我们写一个函数,然后传入参数,要求返回参数,这样的话,按照ts的写法
function get1(val:string):string{
return val
}
function get2(val:number):number{
return val
}
//这样就很麻烦,但是我们可以用any
function get3(val:any):any{
return val
}
//但是any的话,就相当于放弃了类型检验,然而泛型支持不特定的数据类型
function get4<T>(val:T):T{
return val
}
//可以用任意大写字母,但是要相同。
get4<number>(123)//写的东西要相互对应
ok,基本上就了解了吧,其实这样的话基本上就可以写项目了,如果大家还想去更加深入的了解的话,可以去看其他大佬的TypeScript讲解
在vue3使用TypeScript
那我们就直接在vue3中讲解哈。
首先我们要创建vue3+TypeScript的项目,自己创建哈,打开文件,然后进入App.vue文件,你会发现它自动引入defineComponent,那么就有一个问题defineComponent是什么,其实defineComponent本身的功能很简单,但是最主要的功能是为了TypeScript下的类型推到。对于一个 ts 文件如果我们直接写export default {},
这个时候,对于编辑器而言,{} 只是一个 Object 的类型,无法有针对性的提示我们对于 vue 组件来说 {} 里应该有哪些属性。但是增加一层 defineComponet 的话,export default defineComponent({})这时,{} 就变成了 defineComponent 的参数,那么对参数类型的提示,就可以实现对 {} 中属性的提示,外还可以进行对参数的一些类型推导等操作。
上次讲过,我们在vue3中定义响应式数据的话会使用
reactive和ref,那么我们就用接口的形式来定义reactive(上面讲过了什么是接口)
//第一种写法
<script lang="ts">
import { defineComponent, reactive } from 'vue';
interface User{
name:string,
age:number,
say(username:string):void
}
export default defineComponent({
name: 'Home',
setup(){
let fullname:User=reactive({
name:'张三',
age:20,
say(username:string){
console.log(username)
}
})
return{
}
}
});
</script>
我们换一种写法,我们在reactive上ctrl+鼠标左键,进入源码,
我们可以看到,它用的是泛式,之前说过泛式,那么我们可以用泛式的写法来约束代码
<script lang="ts">
import { defineComponent, reactive } from 'vue';
interface User{
name:string,
age:number,
say(username:string):void
}
export default defineComponent({
name: 'Home',
setup(){
//第二种写法
let fullname=reactive<User>({
name:'张三',
age:20,
say(username:string){
console.log(username)
}
})
//第三种写法
let fullname=reactive({
name:'张三',
age:20,
say(username:string){
console.log(username)
}
})as User
return{
}
}
});
</script>
那么去查看ref的源码,也可以用泛型的方式
let num=ref<number|string>('999')
let nums:string=ref('999')//错误写法,不能分配
函数中使用返回值写法(与之前是一样的)
function fn():string{
return '1562'
}
//当然,泛型也是可以的
function fn<T>(val:T):T{
return val
}
emmm,感觉好水哦,我在想想之前vue3还有什么没有讲到的
vue3使用vueX
之前不是讲过在vue3中使用router,其实是和它一样的没有了this.$store,要使用useStore来代替
import {useStore} from 'vuex'
let store=useStore()
完整代码,当然这只是在vue3中用js来写
//在vuex里面代码
import { createStore } from 'vuex'
export default createStore({
state: {
count:1,
list:['张三','李四'],
name:'王五'
},
mutations: {//方法
setCount(state){
state.count++
},
setMsg(state,num){
state.count=num
}
},
getters:{//计算属性
num(state){
return state.count+10
}
},
actions: {//执行mutations的方法,异步操作
inCount(context){
context.commit('setCount')
},
setMsg({commit},num){
commit("setMsg",num)
}
}
})
<!-- 在其他页面使用 -->
<template>
<div class="home">
{{$store.state.count}}
<br>
<button @click="fn">mutations方法</button>
<br>
{{num}}
<br>
<button @click="inCount">actions方法</button>
<button @click="setMsg(50)">actions方法,传值</button>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import {useStore,} from 'vuex'
export default defineComponent({
name: 'Home',
setup(){
let store=useStore()
console.log(store.state.count)
//方法
let fn=()=>{
store.commit('setCount')
}
// 计算属性
let num=computed(()=>{
return store.getters.num
})
// 执行mutations的方法,异步操作
let inCount=()=>{store.dispatch('inCount')}
//执行mutations的方法,异步操作传值
// let setMsg=(num:number)=>{store.dispatch('setMsg',num)}
//方法
let setMsg=(num)=>{store.commit('setMsg',num)}
return{
fn,
num,
inCount,
setMsg
}
}
});
</script>
如果在vue3中用TS来写vuex的话,要进入官网去看引入的东西(有一说一,我是直接翻译的,就不给你们翻译了,自己去)然后在state里面定义的数据都要在interface State里声明,
//存代码
import { InjectionKey } from 'vue'
import { Store,createStore } from 'vuex'
export interface State {
count:number,
list:string[],
name:string
}
export const key: InjectionKey<Store<State>> = Symbol()
export const store= createStore<State>({
state:{
count:1,
list:['张三','李四'],
name:'王五'
},
mutations: {//方法
setCount(state:any){
state.count++
},
setMsg(state:any,num:number){
state.count=num
}
},
getters:{//计算属性
num(state:any){
return state.count+10
}
},
actions: {//执行mutations的方法,异步操作
inCount(context){
context.commit('setCount')
},
setMsg({commit},num){
commit("setMsg",num)
}
}
})
<template>
<div class="home">
{{$store.state.count}}
<br>
<button @click="fn">mutations方法</button>
<br>
{{num}}
<br>
<button @click="inCount">actions方法</button>
<button @click="setMsg(50)">actions方法,传值</button>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import {useStore} from 'vuex'
import { key } from '../store'
export default defineComponent({
name: 'Home',
setup(){
let store=useStore(key)
console.log(store.state.count)
//方法
let fn=():void=>{
store.commit('setCount')
}
// 计算属性
let num=computed(()=>{
return store.getters.num
})
// 执行mutations的方法,异步操作
let inCount=()=>{store.dispatch('inCount')}
//执行mutations的方法,异步操作传值
// let setMsg=(num:number)=>{store.dispatch('setMsg',num)}
//方法
let setMsg=(num:any)=>{store.commit('setMsg',num)}
return{
fn,
num,
inCount,
setMsg
}
}
});
</script>
有一说一,我觉得没必要用ts来写vuex,写的感觉还麻烦了很多
好水哦,算了,后面在修改吧,反正写的很基础,按照我的方式写就不会出现问题,最近没有心情分析代码,下次注意