Vue+TypeScript 入门小问题汇总

3,115 阅读3分钟

Vue + TypeScript

*.d.ts

*.d.ts类型文件不需要手动引入,TypeScript会自动加载。TypeScript 默认只识别 *.ts 文件,不识别 *.vue 文件,因此需要告诉TypeScript*.vue文件交给vue编辑器来处理。
解决方案就是在创建一个vue-shims.d.ts文件:

declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

vue装饰器

vue-class-component

强化 Vue 组件,使用 TypeScript/装饰器 增强 Vue 组件

vue-property-decorator

vue-class-component 上增强更多的结合 Vue 特性的装饰器。

  • @Emit
  • @Inject
  • @Model
  • @Prop
  • @Provide
  • @Watch
  • @Component (从 vue-class-component 继承)

vuex-class

基于vue-class-component对Vuex提供的装饰器。它的作者同时也是vue-class-component的主要贡献者,质量还是有保证的。
ts对vuex的支持不是很好。在TypeScript里面使用不了mapState、mapGetters等方法,只能一个变量一个变量的去引用,这个要麻烦不少。不过使用vuex-class库之后,写法上也还算简洁美观

export default class modules extends Vue {
  @State login: boolean; // 对应this.$store.state.login
  @State headline: StoreState.headline[]; // 对应this.$store.state.headline
  private swiperOption: Object = {
    autoplay: true,
    loop: true,
    direction: "vertical"
  };
  logoClick(): void {
    alert("点我干嘛");
  }
}

十万个为什么?

1. 引入/下载第三方库,为什么仍然提醒找不到?

TypeScript是模仿Node.js运行时的解析策略来在编译阶段定位模块定义文件。 因此,TypeScript在Node解析逻辑基础上增加了TypeScript源文件的扩展名( .ts.tsx.d.ts)。 同时,TypeScript在 package.json里使用字段"types"来表示类似"main"的意义 - 编译器会使用它来找到要使用的"main"定义文件。        ("typings""types"具有相同的意义,也可以使用它。同样要注意的是如果主声明文件名是index.d.ts并且位置在包的根目录里(与index.js并列),就不需要使用"types"属性指定了。)
比如,有一个导入语句import { b } from "./moduleB"/root/src/moduleA.ts里,会以下面的流程来定位"./moduleB"

  • /root/src/moduleB.ts
  • /root/src/moduleB.tsx
  • /root/src/moduleB.d.ts
  • /root/src/moduleB/package.json (如果指定了"types"属性)
  • /root/src/moduleB/index.ts
  • /root/src/moduleB/index.tsx
  • /root/src/moduleB/index.d.ts

回想一下Node.js先查找moduleB.js文件,然后是合适的package.json,再之后是index.js
类似地,非相对的导入会遵循Node.js的解析逻辑,首先查找文件,然后是合适的文件夹。 因此 /root/src/moduleA.ts文件里的import { b } from "moduleB"会以下面的查找顺序解析:

  • /root/src/node_modules/moduleB.ts
  • /root/src/node_modules/moduleB.tsx
  • /root/src/node_modules/moduleB.d.ts
  • /root/src/node_modules/moduleB/package.json (如果指定了"types"属性)
  • /root/src/node_modules/moduleB/index.ts
  • /root/src/node_modules/moduleB/index.tsx
  • /root/src/node_modules/moduleB/index.d.ts
  • /root/node_modules/moduleB.ts
  • /root/node_modules/moduleB.tsx
  • /root/node_modules/moduleB.d.ts
  • /root/node_modules/moduleB/package.json (如果指定了"types"属性)
  • /root/node_modules/moduleB/index.ts
  • /root/node_modules/moduleB/index.tsx
  • /root/node_modules/moduleB/index.d.ts
  • /node_modules/moduleB.ts
  • /node_modules/moduleB.tsx
  • /node_modules/moduleB.d.ts
  • /node_modules/moduleB/package.json (如果指定了"types"属性)
  • /node_modules/moduleB/index.ts
  • /node_modules/moduleB/index.tsx
  • /node_modules/moduleB/index.d.ts

因此,若是有些库没有提供typescript的声明,需要使用者手动去添加。
即在src/typings目前下建一个tools.d.ts文件,声明这个模块即可

declare module 'vue-lazyload'

2. prop为什么一直都是undefined?

必须要使用vue-class-component而不是vue-property-decorator的Component。

import Component from "vue-class-component";
import { Prop, Vue, Watch } from "vue-property-decorator";

后来排查问题,发现是因为我使用了两个装饰器的“合并写法”(即错误写法)

image.png





正确的写法:

image.png

image.png

3. prop的默认值是空对象为什么始终不起效?

大括号在js中是块作用域,因此会产生歧义,是块作用域呢还是返回空对象呢。因此,需要包一层小括号。像数组之类的就不会有歧义了,因此可以直接返回。

// 错误
@Prop({
    default: () => {}
  })
  private value!: any;

// 正确
@Prop({
    default: () => ({})
  })
  private value!: any;

4. 为什么import vue组件时,一切都对的,就是cannot find module?

必须带上后缀.vue!因为ts只认识.ts。

5. 为什么申明了一个接口类型,但是还是报错Cannot find name?

即使声明文件不需要导出任何东西,仍然需要导出一个空对象,用来告诉编译器这是一个模块的声明文件,而不是一个全局变量的声明文件。