创建项目
新建一个基于ts的vue项目
vue create xxx
如下配置勾选TS
在已存在的项目中安装typescript
vue add @vue/typescript
TS语法特点
- 类型注解、类型检测
- 类
- 接口
- 泛型
类型注解和编译时类型检查
使用类型注解约束变量类型,编译器可以做静态类型检查,使程序更加健壮
// 类型注解
let var1: string;
var1 = "慧永诺" //正确
var1 = 4 //错误
// 编译器类型推断可省略这个语法
let var2 = true;
var2 = 1 //错误
//类型数组
let arr: string[];
arr = ['hello','world']; //正确
arr = [1,2] //错误
// 任意类型any
let varAny: any;
varAny = 1;
varAny = 'asd'
// any类型也可用于数组
let arrAny: any[];
arrAny = ['1',3,true]
// 函数中的类型约束 person: string代表参数类型 (person: string): string代表返回值类型
function greet(person: string): string{
return person + 'hello';
}
//函数中必填参:参数一旦声明,就要求传递,且类型须符合;可选参:参数名后面加上问号;默认值:直接赋值
function greeting(person: string, msg = '', desction?: string): string{
if(desction){
return person + msg + desction + 'hello'
}else{
return person + msg + 'hello';
}
}
// void类型,常用于没有返回值的函数
function warn(person: string): void{
}
// 使用类型别名自定义类型
let objType: {foo: string, bar: string}
objType = {foo: '1',bar: '2add'}
// 使用type定义类型别名,使用更便捷,还能复用
type Foobar = {foo: string, bar: string}
let aliasType: Foobar;
// 联合类型:希望某个变量或参数的类型是多种类型其中之一
let union: string | number;
union = '1'; //正确
union = 1 //正确
// 交叉类型:想要定义某种由多种类型合并而成的类型使用交叉类型
type First = {first: number};
type Second = {second: number};
// FirstSecond将同时拥有属性first和second
type FirstSecond = First & Second
类class的特性
ts中的类和es6中的类大体相同,重点介绍一下ts中类的访问控制这一特性
class Parent{
private work = 'work'; //私有属性,不能在类的外部访问
protected money = 'money'; //保护属性,可以在子类中访问
// 参数属性:构造函数参数加修饰符,能够定义为成员属性
constructor(public appearance = 'appearance'){}
// 方法也有修饰符
private someMethod(){
console.log('111')
}
//存取器:属性方式访问,可添加额外逻辑,控制读写性
// 除了public可以直接访问,其他私有属性通过get方法才能外部访问
get fool(){
return this.foo
}
set fool(val){
this.foo = val
}
}
class Child extends Parent{
log(){
console.log(this.money)
}
}
接口 interface
接口仅约束结构,不要求实现,使用更简单;接口中只需要定义结构,不需要初始化,和上方的type aliases
无特殊区别,写库的时候会推荐使用interface,因为他出现的更早
//Person接口定义了结构
interface Person{
firstName: string;
lastName: string;
}
//greeting函数通过Person接口约束参数结构
function greeting(person: Person){
return 'Hello,' + person.firstName +person.lastName;
}
greeting({firstName: 'Zhang',lastName: 'San'}); //正确
greeting({firstName: 'Zhang'}); //错误
泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。以次增加代码通用性
泛型优点:
- 函数和类可以支持多种类型,更加通用
- 不必编写多条重载,冗长类和类型,可读性好
- 灵活控制类型约束 不仅通用且能灵活控制,泛型被广泛应用于通用库的编写
//使用泛型
interface Result<T> {
ok: 0 | 1;
data: T
}
//泛型方法
function getResult<T> (data: T): Result<T>{
return data
}
//用尖括号方式指定T为string
getResult<string>('hello')
//用类型推断指定T为number
getResult(1)
声明文件
使用ts开发时如果要使用第三方js库的同时还想利用ts诸如类型检查等特性就需要声明文件,类似
xx.d.ts
同时vue项目中还可以在shims-vue.d.ts中对已存在模块进行补充
示例1:利用模块补充$axios属性到vue示例,从而在组件中直接使用
//main.ts
//在没有用ts的vue中,挂载在Vue.prototype上就可以直接使用了
import Vue from 'vue';
import axios from 'axios';
Vue.prototype.$axios = axios
//shims-vue.d.ts
//ts中还需要对模块补充声明,才能在组件中直接使用
import Vue from 'vue';
import {AxiosInstance} from "axios";
declare module '*.vue' {
export default Vue
}
// 声明:扩展模块
declare module "vue/types/vue" {
interface Vue{
$axios: AxiosInstance
}
}
示例2:在以存在的项目中替换为ts,比如router/index.js
,js文件我们需要编写声明文件router/index.d.ts
import VueRouter from 'vue-router';
declare const router: VueRouter
export default router
装饰器
装饰器用于扩展类或者它的属性和方法。@xxx 就是装饰器的写法
下列用的装饰器需要导入 import {Componen,Prop,Emit,Watch} from "vue-property-decorator";
@Component
创建vue组件,ts写法如下:
<script lang="ts">
import {Componen} from "vue-property-decorator";
@Component
export default class Hello extends Vue{}
</script>
那么组件中的components怎么声明呢?
在@Component
中添加参数@Component({components:{xxx,xxx}})
@Prop
采用@Prop的方式声明组件属性
@Component
export default class Hello extends Vue{
// @Prop()参数是为vue提供属性选项
// ! 称为明确赋值断言
@Prop({type: String, required: true})
msg!: string
}
@Emit
派发事件
//HelloWorld.vue
// 通知父类新增事件,若未指定事件名则函数名作为事件名(父类以羊肉串形式调用); @Emit('事件名')
@Emit()
addFeature(event: any){
//e.target是EventTarget类型,需要断言为HTMLInputElement
const inp = event.target as HTMLInputElement;
const feature = {id: this.features.length + 1,name: inp.value,selected:true};
this.features.push(feature);
event.target.value = '';
return feature;
}
//App.vue 父类接收事件
<template>
<HelloWorld @add-feature="addFeature"></HelloWorld>
</template>
<script lang="ts">
@Component({components:{HelloWorld}})
export default class App extends Vue{
addFeature(feature: FeactureSelect) {
console.log('新增了一个特性', feature.name);
}
}
</script>
@Watch
@Watch('msg')
onMsgChange(val: string,oldVal: any){
console.log(val,oldVal);
}
data()在ts中怎么写?
//之前js写法
data(){
return{
features:[{id:1,name:"张三",selected:true},{id:2,name:"李四",selected:false}];
}
}
//ts写法省去了定义data
features: FeactureSelect[] = [{id:1,name:"张三",selected:true},{id:2,name:"李四",selected:false}];
methods在ts中怎么写?
//之前js写法
methods:{
greet(person,msg){
if(! msg){
console.log(person + 'hello')
}else{
console.log(person + msg + 'hello')
}
}
}
//ts写法省去了定义methods
greet(person: string,msg?: string): void{
// return person + 'hello';
if(! msg){
console.log(person + 'hello')
}else{
console.log(person + msg + 'hello')
}
}
computed在ts中怎么写?
//js写法
computed:{
count(){
return this.features.length;
}
}
//ts写法
// 定义getter作为计算属性
get count(){
return this.features.length;
}
生命周期在ts中怎么调用?
//和之前写法无异
created(){
const parent = new Parent()
console.log(parent.fool)
}
vuex状态管理
vuex-module-decorators
通过装饰器提供模块化声明vuex模块的方法。
-
安装
npm i vuex-module-decorators -D
-
根模块清空,修改
store/index.ts
export default new Vuex.store({})
-
定义user模块,创建
store/counter
import { Module, VuexModule, Mutation, Action, getModule } from 'vuex-module-decorators'
import store from './index'
// 动态注册模块
@Module({ dynamic: true, store: store, name: 'user', namespaced: true })
class UserrModule extends VuexModule {
token:localStorage.getItem('token');
@Mutation
setToken(token) {
//通过this直接访问token
this.token = token
}
//定义getters
get tokenMi() {
return this.count + 'sadasd';
}
@Action
login(userinfo) {
return login(userinfo).then(res => {
this.setToken(res.data);
localStorage.setItem("token", res.data);
});
}
}
export default getModule(UserModule)
//使用,App.vue
//第一种
<p>{{$store.state.user.token}}</p>
//第二种
<template>
<p @click="setToken()">{{UserModule.token}}</p>
</template>
<script type="ts">
import UserModule from '@/store/user';
@Component({components:{HelloWorld}})
export default class App extends Vue{
setToken(){
UserModule.login()
}
}
</script>