VUE中应用TypeScript(上)
Posted 前端菜鸟逆袭架构师
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VUE中应用TypeScript(上)相关的知识,希望对你有一定的参考价值。
资源
1. TypeScript参考:http://www.typescriptlang.org
2. Vue+TypeScript:https://cn.vuejs.org/v2/guide/typescript.html
知识点
1. ts核心语法
2. ts+vue
3. 装饰器应用
4. 装饰器原理
5. vue-property-decorator源码解析
准备工作
新建一个基于ts的vue项目
在已存在项目中安装typescript
命令:vue add @vue/typescript
请暂时忽略引发的几处Error,它们不会影响项目运行,我们将在后面处理它们。
TS特点
类型注解、类型检测
类
接口
泛型
装饰器
类型声明
类型注解和编译时类型检查
使用类型注解约束变量类型,编译器可以做静态类型检查,使程序更加健壮
类型基础
main.js中引入:
let var1: string; // 类型注解
var1 = "尤雨溪真帅"; // 正确
var1 = 4; // 错误
// 编译器类型推断可省略这个语法
let var2 = true;
var2 = 4; // 错误
// 常见原始类型: string,number,boolean,undefined,null,symbol
// 类型数组
let arr: string[];
arr = ['Tom']; // 或Array<string>
// 任意类型any
let varAny: any;
varAny = 'xx';
varAny = 3;
// any类型也可用于数组
let arrAny: any[];
arrAny = [1, true, "free"];
arrAny[1] = 100;
// 函数中的类型约束
function greet(person: string): string {
return 'hello, ' + person;
}
// void类型,常用于没有返回值的函数
function warn(): void {}
范例,HelloWorld.vue
<template>
<div>
<ul>
<li v-for="feature in features" :key="feature">{{feature}}</li>
</ul>
</div>
</template>
<script lang='ts'>
import { Component, Prop, Vue } from "vue-property-decorator";
//方式一:class-style(用的比较多)
@Component
export default class Hello extends Vue {
@Prop() private msg!:string;
//属性将成为data中数据
features: string[] = ["类型注解", "编译型语言"];
}
//方式二:option-style(官方:该方式会稍微有点问题)
import Vue form 'vue'
export default Vue.extend({data(this)})
//this出现导致ts编译无法知道一些动态属性,经常情况下this.$XX,导致很难推断
</script>
方式三:jsx方式
特点:上下文很清楚;代码提示很强,可以做类型检测
使用:
类型别名
使用类型别名自定义类型
// 可以用下面这样方式定义对象类型
const objType: { foo: string, bar: string }
// 使用type定义类型别名,使用更便捷,还能复用
type Foobar = { foo: string, bar: string }
const aliasType: Foobar
接口和类型别名是可以互换的,没有什么区别。对ide有影响,程序本身没影响。2.7版本之前不支持类型别名。对于通用性来讲,接口比别名更好一些。
范例:使用类型别名定义Feature,types/index.ts
export type Feature = {
id: number,
name: string
}
使用自定义类型,HelloWorld.vue
<template>
<div>
<!--修改模板-->
<li v-for="feature in features" :key="feature.id">{{feature.name}}</li>
</div>
</template>
<script lang='ts'>
// 导入接口
import { Feature } from "@/types";
@Component
export default class Hello extends Vue {
// 修改数据结构
features: Feature[] = [{ id: 1, name: "类型注解" }]; }
</script>
联合类型
希望某个变量或参数的类型是多种类型其中之一
let union: string | number;
union = '1'; // ok
union = 1; // ok
使用:扩大范围:
交叉类型
想要定义某种由多种类型合并而成的类型使用交叉类型
type First = {first: number};
type Second = {second: number};
// FirstAndSecond将同时拥有属性first和second
type FirstAndSecond = First & Second;
范例:利用交叉类型给Feature添加一个selected属性
// types/index.ts
export type Feature={
id:number;
name:string;
}
type Select = {
selected: boolean
}
export type FeatureSelect = Feature & Select
使用:
使用这个FeatureSelect,HelloWorld.vue
features: FeatureSelect[] = [
{ id: 1, name: "类型注解", selected: false },
{ id: 2, name: "编译型语言", selected: true }
];
<li :class="{selected: feature.selected}">{{feature.name}}</li>
.selected {
background-color: rgb(168, 212, 247);
}
函数
必填参:参数一旦声明,就要求传递,且类型需符合
function greeting(person: string): string {
return "Hello, " + person;
}
greeting('tom')
可选参数:参数名后面加上问号,变成可选参数
function greeting(person: string, msg?: string): string {
return "Hello, " + person;
}
默认值(默认值与?可选冲突)默认值与可选参数放在必须参数后面
function greeting(person: string, msg = ''): string {
return "Hello, " + person;
}
*函数重载:以参数数量或类型区分多个同名函数,先声明,再实现。
// 重载1
function watch(cb1: () => void): void;
// 重载2
function watch(cb1: () => void, cb2: (v1: any, v2: any) => void): void;
// 实现
function watch(cb1: () => void, cb2?: (v1: any, v2: any) => void) {
if (cb1 && cb2) {
console.log('执行watch重载2');
} else {
console.log('执行watch重载1');
}
}
范例:新增特性,Hello.vue
<div>
<input type="text" placeholder="输入新特性" @keyup.enter="addFeature">
</div>
addFeature(e: KeyboardEvent) {
//类型断言
// e.target是EventTarget类型,需要断言为HTMLInputElement
const inp = e.target as HTMLInputElement;
const feature: FeatureSelect = {
id: this.features.length + 1,
name: inp.value,
selected: false
}
this.features.push(feature);
inp.value = "";
}
范例:生命周期钩子,Hello.vue
created() {
this.features = [{ id: 1, name: "类型注解" }];
}
类
class的特性
ts中的类和es6中大体相同,这里重点关注ts带来的访问控制等特性
class Parent {
private _foo = "foo"; // 私有属性,不能在类的外部访问
protected bar = "bar"; // 保护属性,可以在子类中访问
// 参数属性:构造函数参数加修饰符,能够定义为成员属性
constructor(public tua = "tua") {}
// 方法也有修饰符
private someMethod() {}
// 存取器:属性方式访问,可添加额外逻辑,控制读写性
get foo() {
return this._foo;
}
set foo(val) {
this._foo = val;
}
}
范例:利用getter设置计算属性,Hello.vue
<template>
<li>特性数量:{{count}}</li>
</template>
<script lang="ts">
export default class HelloWorld extends Vue {
// 定义getter作为计算属性
get count() {
return this.features.length;
}
}
</script>
接口
接口仅约束结构,不要求实现,使用更简单
// Person接口定义了结构
interface Person {
firstName: string;
lastName: string;
}
// greeting函数通过Person接口约束参数解构
function greeting(person: Person) {
return 'Hello, ' + person.firstName + ' ' + person.lastName;
}
greeting({firstName: 'Jane', lastName: 'User'}); // 正确
greeting({firstName: 'Jane'}); // 错误
范例:Feature也可用接口形式约束,./types/index.ts
// 接口中只需定义结构,不需要初始化
export interface Feature {
id: number;
name: string;
}
Interface vs type aliases:https://www.typescriptlang.org/docs/handbook/advanced-types.html#interfaces-vs-type-aliases
恭喜你,今天又进步了一点点!
以上是关于VUE中应用TypeScript(上)的主要内容,如果未能解决你的问题,请参考以下文章
Vue+Typescript中在Vue上挂载axios使用时报错
Vue + VueX + Typescript + Vue 路由器。组件未销毁
如何在 Vue 和 TypeScript 应用中正确的全局注册 axios