vue3中使用TypeScript

7,923 阅读8分钟

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

如果前期定义了类型是什么,后期就赋值相对应类型,如果赋值不是相对应类型,那么会报错 1637310326(1).jpg 接口:什么是接口,接口也是一种类型, 也是用来约束使用者的,他的作用是进一步定义对象内的各种属性。

其他补充

  • 接口:接口是一种规范的定义,它定义了行为和动作的规范
//接口,比如说定义的东西用过很多次,那就可以用到接口,?是代表不确定有没有这个参数(可选值)
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 的参数,那么对参数类型的提示,就可以实现对 {} 中属性的提示,外还可以进行对参数的一些类型推导等操作。

1637304716(1).jpg 上次讲过,我们在vue3中定义响应式数据的话会使用reactiveref,那么我们就用接口的形式来定义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+鼠标左键,进入源码,

1637495364(1).jpg

我们可以看到,它用的是泛式,之前说过泛式,那么我们可以用泛式的写法来约束代码

<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,写的感觉还麻烦了很多

好水哦,算了,后面在修改吧,反正写的很基础,按照我的方式写就不会出现问题,最近没有心情分析代码,下次注意

🎉🎉完结撒花🎉🎉