<template> <p>特性数量:{{count}}</p> </template> <script lang="ts"> export default class Demo extends Vue { // 定义 getter 作为计算属性 get count () { return this.features.length; } } </script>
接口
接口仅约束结构,不要求实现
interface Person { firstName: string; lastName: string; } function greeting (person: Person) { return `Hello, ${person.firstName} ${person.lastName}`; } const user = {firstName: 'Jane', lastName: 'user'}; console.log(greeting(user));
案例:vue demo,声明接口类型约束数据结构
<template> <li v-for="feature in features" :key="feature.id">{{feature.name}}</li> </template> <script lang="ts"> // 定义一个接口约束feature的数据结构 interface Feature { id: number; name: string; } export default class Demo extends Vue { private features: Feature[]; constructor () { super(); this.features = [ {id: 1, name: '类型注解'}, {id: 2, name: '类型推论'}, {id: 3, name: '编译型语言'} ] } } </script>
泛型
泛型 是指在定义函数、接口或类的时候,不预先指定具体的类,而是在使用时才指定类型的一种特性。
interface Result<T> { data: T; } // 不使用泛型 interface Result { data: Feature[]; }
案例:使用泛型约束接口返回类型
function getData<T>(): Result<T> { const data: any = [ {id: 1, name: '类型注解'}, {id: 2, name: '类型推论'}, {id: 3, name: '编译型语言'} ]; return {data}; } // 调用 this.features = getData<Feature[]>().data;
案例:使用泛型约束接口返回类型 Promise
function getData<T>(): Promise<Result<T>> { const data: any = [ {id: 1, name: '类型注解'}, {id: 2, name: '类型推论'}, {id: 3, name: '编译型语言'} ]; return Promise.resolve<Result<T>>({data}); } // 调用 async 方式 async mounted () { this.features = (await getData<Feature[]>()).data; } // 调用 then 方式 mouted () { getData<Feature[]>().then((res: Result<Feature[]>) => { this.features = res.data; }) }
装饰器
装饰器用于扩展类或者它的属性和方法。
属性声明:@Prop
除了在 @Component 中声明,还可以采用@Prop的方式声明组件属性
export default class Demo extends Vue { // Props() 参数是为 vue 提供属性选项 // !称为明确赋值断言,它是提供给ts的 @Prop({type: String, require: true}) private msg!: string; }
事件处理:@Emit
// 通知父类新增事件,若未指定事件名则函数名作为事件名(驼峰变中划线分隔) @Emit() private addFeature(event: any) {// 若没有返回值形参将作为事件参数 const feature = { name: event.target.value, id: this.features.length + 1 }; this.features.push(feature); event.target.value = ""; return feature;// 若有返回值则返回值作为事件参数 }
template 模板组件上正常写,@add-feature
变更监测:@Watch
@Watch('msg') onRouteChange(val:string, oldVal:any){ console.log(val, oldVal); }
装饰器原理
装饰器本质是工厂函数,修改传入的类、方法、属性等
类装饰器
// 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。 function log(target: Function) { // target是构造函数 console.log(target === Foo); // true target.prototype.log = function() { console.log(this.bar); } // 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。 } @log class Foo { bar = 'bar' } const foo = new Foo(); // @ts-ignore foo.log();
实战一下 Component,新建 Decor.vue
<template> <div>{{msg}}</div> </template> <script lang='ts'> import { Vue } from "vue-property-decorator"; function Component(options: any) { return function(target: any) { return Vue.extend(options); }; } @Component({ props: { msg: { type: String, default: "" } } }) export default class Decor extends Vue {} </script>
源码简单了解
类装饰器主要依赖库:vue-class-component,深入源码,了解其背后究竟做了什么。
vue-property-decorator.js
import Vue from 'vue'; import Component, { createDecorator, mixins } from 'vue-class-component'; export { Component, Vue, mixins as Mixins };
createDecorator、applyMetadata 是核心,后续实现都依赖它,比如 Prop、Watch、Ref。
Prop 源码实现: