新建工程
- 新建工程时 选择 typescript

- 在已有项目上 使用
vue add @vue/typescript

package.json多了一些依赖
"dependencies": {"vue-class-component": "^7.2.3","vue-property-decorator": "^9.1.2"},"devDependencies": {"@typescript-eslint/eslint-plugin": "^4.18.0","@typescript-eslint/parser": "^4.18.0","@vue/cli-plugin-typescript": "^4.5.13","@vue/eslint-config-typescript": "^7.0.0","typescript": "~4.1.5",},
tsconfig.json
{// 编译选项"compilerOptions": {"target": "esnext", // 编译输出目标 ES 版本"module": "esnext", // 采用的模块系统"strict": true,// 以严格模式解析"jsx": "preserve","importHelpers": true, // 从 tslib 导入外部帮助库: 比如__extends,__rest等"moduleResolution": "node", // 如何处理模块"experimentalDecorators": true, // 启用装饰器"esModuleInterop": true,"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入"strictPropertyInitialization" : false, // 定义一个变量就必须给它一个初始值"allowJs": true, // 允许编译javascript文件"sourceMap": true, // 是否包含可以用于 debug 的 sourceMap"noImplicitThis": false, // 忽略 this 的类型检查, Raise error on this expressions with an implied any type."baseUrl": ".", // 解析非相对模块名的基准目录"pretty": true,// 给错误和消息设置样式,使用颜色和上下文。"types": ["webpack-env"], // 设置引入的定义文件// 指定特殊模块的路径"paths": {"@/*": ["src/*"]},// 编译过程中需要引入的库文件的列表"lib": ["esnext", "dom", "dom.iterable", "scripthost"]},// ts 管理的文件"include": ["src/**/*.ts","src/**/*.tsx","src/**/*.vue","tests/**/*.ts","tests/**/*.tsx"],// ts 排除的文件"exclude": ["node_modules"]}
shims-vue.d.ts:主要用于 TS 识别.vue 文件
declare module '*.vue' {import Vue from 'vue'export default Vue}
shims-tsx.d.ts:允许.tsx 结尾的文件
import Vue, { VNode } from 'vue'declare global {namespace JSX {// tslint:disable no-empty-interfaceinterface Element extends VNode {}// tslint:disable no-empty-interfaceinterface ElementClass extends Vue {}interface IntrinsicElements {[elem: string]: any}}}
使用ts开发时如果要使用第三方js库的同时还想利用ts诸如类型检查等特性就需要声明文件,类似xx.d.ts
同时,vue项目中还可以在shims-vue.d.ts中对已存在模块进行补充npm i @types/xxx
范例:利用模块补充$axios属性到Vue实例,从而在组件里面直接用:
// main.tsimport axios from 'axios'Vue.prototype.$axios = axios;
// shims-vue.d.tsimport Vue from "vue";import { AxiosInstance } from "axios";declare module "vue/types/vue" {interface Vue {$axios: AxiosInstance;}}
装饰器
https://class-component.vuejs.org/guide/property-type-declaration.html
vue-class-component
import Vue from 'vue'import Component from 'vue-class-component'@Componentexport default class HelloWorld extends Vue {// Declared as component datamessage = 'Hello World!'// Declared as component methodhello() {console.log(message)}// Declared as computed property getterget message() {return this.message}// Declared as computed property setterset message(value) {this.message = value}beforeRouteEnter(to, from, next) {console.log('beforeRouteEnter')next()}beforeRouteUpdate(to, from, next) {console.log('beforeRouteUpdate')next()}beforeRouteLeave(to, from, next) {console.log('beforeRouteLeave')next()}}
mixins
// mixins.jsimport Vue from 'vue'import Component from 'vue-class-component'// You can declare mixins as the same style as components.@Componentexport class Hello extends Vue {hello = 'Hello'}@Componentexport class World extends Vue {world = 'World'}import Component, { mixins } from 'vue-class-component'import { Hello, World } from './mixins'// Use `mixins` helper function instead of `Vue`.// `mixins` can receive any number of arguments.@Componentexport class HelloWorld extends mixins(Hello, World) {created () {console.log(this.hello + ' ' + this.world + '!') // -> Hello World!}}
vue-property-decorator
vue-property-decorator 是在 vue-class-component 上增强了更多的结合 Vue 特性的装饰器,新增了这 7 个装饰器:
- @Emit
- @Inject
- @Model
- @Prop
- @Provide
- @Watch
- @Component (从 vue-class-component 继承) ```typescript import { Component, Emit, Inject, Model, Prop, Provide, Vue, Watch } from ‘vue-property-decorator’ import HelloWorld from ‘./components/HelloWorld.vue’;
@Component({ components: { HelloWorld, }, }) export class MyComponent extends Vue { @Prop(String) propA:string;
@Watch(‘child’) onChildChanged(val: string, oldVal: string) { } }
```typescriptimport HelloWorld from './components/HelloWorld.vue';export default {components:{HelloWorld},props: {propA: String,}methods: {onChildChanged(val, oldVal) { }},watch: {'child': {handler: 'onChildChanged',immediate: false,deep: false}}}
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;// 若有返回值则返回值作为事件参数}
原理
装饰器是加工厂函数,它能访问和修改装饰目标
//类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。function log(target: Function) {// target是构造函数console.log(target === Foo); // truetarget.prototype.log = function() {console.log(this.bar);}}@logclass Foo {bar = 'bar'}const foo = new Foo();// @ts-ignorefoo.log();
