新建工程

  • 新建工程时 选择 typescript

image.png

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

image.png

package.json多了一些依赖

  1. "dependencies": {
  2. "vue-class-component": "^7.2.3",
  3. "vue-property-decorator": "^9.1.2"
  4. },
  5. "devDependencies": {
  6. "@typescript-eslint/eslint-plugin": "^4.18.0",
  7. "@typescript-eslint/parser": "^4.18.0",
  8. "@vue/cli-plugin-typescript": "^4.5.13",
  9. "@vue/eslint-config-typescript": "^7.0.0",
  10. "typescript": "~4.1.5",
  11. },

tsconfig.json

  1. {
  2. // 编译选项
  3. "compilerOptions": {
  4. "target": "esnext", // 编译输出目标 ES 版本
  5. "module": "esnext", // 采用的模块系统
  6. "strict": true,// 以严格模式解析
  7. "jsx": "preserve",
  8. "importHelpers": true, // tslib 导入外部帮助库: 比如__extends__rest
  9. "moduleResolution": "node", // 如何处理模块
  10. "experimentalDecorators": true, // 启用装饰器
  11. "esModuleInterop": true,
  12. "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
  13. "strictPropertyInitialization" : false, // 定义一个变量就必须给它一个初始值
  14. "allowJs": true, // 允许编译javascript文件
  15. "sourceMap": true, // 是否包含可以用于 debug sourceMap
  16. "noImplicitThis": false, // 忽略 this 的类型检查, Raise error on this expressions with an implied any type.
  17. "baseUrl": ".", // 解析非相对模块名的基准目录
  18. "pretty": true,// 给错误和消息设置样式,使用颜色和上下文。
  19. "types": ["webpack-env"], // 设置引入的定义文件
  20. // 指定特殊模块的路径
  21. "paths": {
  22. "@/*": ["src/*"]
  23. },
  24. // 编译过程中需要引入的库文件的列表
  25. "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  26. },
  27. // ts 管理的文件
  28. "include": [
  29. "src/**/*.ts",
  30. "src/**/*.tsx",
  31. "src/**/*.vue",
  32. "tests/**/*.ts",
  33. "tests/**/*.tsx"
  34. ],
  35. // ts 排除的文件
  36. "exclude": ["node_modules"]
  37. }

shims-vue.d.ts:主要用于 TS 识别.vue 文件

  1. declare module '*.vue' {
  2. import Vue from 'vue'
  3. export default Vue
  4. }

shims-tsx.d.ts:允许.tsx 结尾的文件

  1. import Vue, { VNode } from 'vue'
  2. declare global {
  3. namespace JSX {
  4. // tslint:disable no-empty-interface
  5. interface Element extends VNode {}
  6. // tslint:disable no-empty-interface
  7. interface ElementClass extends Vue {}
  8. interface IntrinsicElements {
  9. [elem: string]: any
  10. }
  11. }
  12. }

使用ts开发时如果要使用第三方js库的同时还想利用ts诸如类型检查等特性就需要声明文件,类似
xx.d.ts
同时,vue项目中还可以在shims-vue.d.ts中对已存在模块进行补充
npm i @types/xxx
范例:利用模块补充$axios属性到Vue实例,从而在组件里面直接用:

  1. // main.ts
  2. import axios from 'axios'
  3. Vue.prototype.$axios = axios;
  1. // shims-vue.d.ts
  2. import Vue from "vue";
  3. import { AxiosInstance } from "axios";
  4. declare module "vue/types/vue" {
  5. interface Vue {
  6. $axios: AxiosInstance;
  7. }
  8. }



装饰器

https://class-component.vuejs.org/guide/property-type-declaration.html

vue-class-component

  1. import Vue from 'vue'
  2. import Component from 'vue-class-component'
  3. @Component
  4. export default class HelloWorld extends Vue {
  5. // Declared as component data
  6. message = 'Hello World!'
  7. // Declared as component method
  8. hello() {
  9. console.log(message)
  10. }
  11. // Declared as computed property getter
  12. get message() {
  13. return this.message
  14. }
  15. // Declared as computed property setter
  16. set message(value) {
  17. this.message = value
  18. }
  19. beforeRouteEnter(to, from, next) {
  20. console.log('beforeRouteEnter')
  21. next()
  22. }
  23. beforeRouteUpdate(to, from, next) {
  24. console.log('beforeRouteUpdate')
  25. next()
  26. }
  27. beforeRouteLeave(to, from, next) {
  28. console.log('beforeRouteLeave')
  29. next()
  30. }
  31. }

mixins

  1. // mixins.js
  2. import Vue from 'vue'
  3. import Component from 'vue-class-component'
  4. // You can declare mixins as the same style as components.
  5. @Component
  6. export class Hello extends Vue {
  7. hello = 'Hello'
  8. }
  9. @Component
  10. export class World extends Vue {
  11. world = 'World'
  12. }
  13. import Component, { mixins } from 'vue-class-component'
  14. import { Hello, World } from './mixins'
  15. // Use `mixins` helper function instead of `Vue`.
  16. // `mixins` can receive any number of arguments.
  17. @Component
  18. export class HelloWorld extends mixins(Hello, World) {
  19. created () {
  20. console.log(this.hello + ' ' + this.world + '!') // -> Hello World!
  21. }
  22. }

vue-property-decorator

https://github.com/kaorun343/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) { } }

  1. ```typescript
  2. import HelloWorld from './components/HelloWorld.vue';
  3. export default {
  4. components:{
  5. HelloWorld
  6. },
  7. props: {
  8. propA: String,
  9. }
  10. methods: {
  11. onChildChanged(val, oldVal) { }
  12. },
  13. watch: {
  14. 'child': {
  15. handler: 'onChildChanged',
  16. immediate: false,
  17. deep: false
  18. }
  19. }
  20. }

Emit

  1. // 通知父类新增事件,若未指定事件名则函数名作为事件名(羊肉串形式)
  2. @Emit()
  3. private addFeature(event: any) {// 若没有返回值形参将作为事件参数
  4. const feature = { name: event.target.value, id: this.features.length + 1 };
  5. this.features.push(feature);
  6. event.target.value = "";
  7. return feature;// 若有返回值则返回值作为事件参数
  8. }

原理

装饰器是加工厂函数,它能访问和修改装饰目标

  1. //类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
  2. function log(target: Function) {
  3. // target是构造函数
  4. console.log(target === Foo); // true
  5. target.prototype.log = function() {
  6. console.log(this.bar);
  7. }
  8. }
  9. @log
  10. class Foo {
  11. bar = 'bar'
  12. }
  13. const foo = new Foo();
  14. // @ts-ignore
  15. foo.log();