最近尝试了一下Typescript在Vue项目中的使用,中间遇到了一些问题,把遇到的问题记录一下,以防被忘。
如何让Typescript识别Vue、JSON文件
因为Typescript默认不能识别.vue
文件,导致在引用.vue
文件时,提示加载错误。所以需要自己新建一个 .d.ts
文件添加以下内容。这告诉Typescript以.Vue
结尾的导入的任何东西都与Vue构造函数本身具有相同的形状。
// *.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
复制代码
另外在项目中难免会使用到一些 .json
配置文件,在引用时同样因为Typescript
不能识别,同样也需要自己在 *.d.ts
文件声明。
// .d.ts
declare module "*.json" {
const value: any;
export default value;
}
复制代码
需要注意的时,这些 .d.ts
文件不能放到项目运行入口文件上级目录,否则Typescript没找到这些声明,导致不能正确识别文件类型。
使用装饰器定义组件
在Vue项目中使用Typescript,定义.vue
文件一般使用类似React的Class
形式,所以这里只记录一下在 Class
这种形式的写法。使用这种方式需要使用装饰器来定义组件,这需要额外的两个包 vue-class-component 和 vue-property-decorator,其中vue-property-decorator依赖vue-class-component。这2个包可以让我们使用装饰器来定义组件的方法、属性、watch等内容。
在vue-class-decorator中提供了@Emit、@Inject、Mixins、@Model、@Prop、@Provide、@Watch、@Component,8种装饰器,具体使用方法这里不做过多介绍,具体请看这里。其中Mixins、@Component继承于vue-class-component。
Computed、Data、Methods
这里取消了组件的data和methods属性,以往data返回对象中的属性、methods中的方法需要直接定义在Class
中,当做类的属性和方法。
@Component
export default class HelloDecorator extends Vue {
count: number = 123
increment() {
// xxxx
}
}
复制代码
Computed在这里也被取消,变成了带有get和set的类方法。
@Component
export default class HelloDecorator extends Vue {
count: number = 123
// 获取计算属性
get total(): number {
return this.count + 1
}
// 设置计算属性
set total(param:number): void {
this.count = param
}
}
复制代码
@Component(继承自vue-class-component)
Component装饰器它注明了此类为一个Vue组件,因此即使没有设置选项也不能省略。如果需要定义比如 name、components、filters、directives以及自定义属性,就可以在Component装饰器中定义。
@Component({
name: 'xComponent',
pageName: 'page title', // 自定义属性
components: {
// xxxx
},
filters: {
// xxxx
},
directives: {
// xxxx
}
})
export default class HelloDecorator extends Vue {
}
复制代码
关于组件名,如果不设置name属性,组件名将使用类名。优先级: name > 类名。
在上面我们还定义组件的自定义属性,但Vue并没有提供对自定义属性的声明支持,所以在定义自定义属性时,需要我们在.d.ts
文件中扩展ComponentOptions,声明我们自己定义的属性。
declare module 'vue/types/options' {
interface ComponentOptionsextends Vue> {
// 自定义的属性
pageName?: string;
}
}
复制代码
@Prop
在使用Prop装饰器定义属性时,如果我们打开了tsconfig.js
配置文件中的 strictpropertyinitialize
选项,我们就需要通过附加一个!给定义的属性。这就告诉TypeScript:“嘿,放松,其他人会给这个属性赋值”。如果不这样做的话,TypeScript会告诉你: “嘿,注意,这个属性你还没初始化”。需要注意的是: 给属性设置default值,并不是上面的初始化。 ! 它在延迟初始化或重新初始化的场景下很方便使用。
@Component
export default class YourComponent extends Vue {
@Prop(Number) propA!: number
@Prop({ default: 'default value' }) propB!: string
@Prop([String, Boolean]) propC: string | boolean
}
复制代码
上面的问题同样适用于 @Inject、@Model装饰器。
// @Inject
@Component
export class MyComponent extends Vue {
@Inject() foo!: string
@Inject('bar') bar!: string
@Provide() foo = 'foo'
@Provide('bar') baz = 'bar'
}
// @Model
@Component
export default class YourComponent extends Vue {
@Model('change', { type: Boolean }) checked!: boolean
}
复制代码
$refs的使用
我们经常给元素或组件添加ref属性,以便对元素操作和访问组件的属性和方法。但在这里当我们需要使用$refs时,需要提前声明refs内容的类型,以便Typescript能做出正确的类型判断。
<div ref="div">div>
<e-component ref="cComponent">e-componen>
复制代码
import eComponent form 'xxxx'
@Component({
components: {
'e-component': eComponent
}
})
export default class YourComponent extends Vue {
// 注意这里的感叹号
$refs!: {
div: HTMLDivElement, // html元素
cComponent: eComponent // Typescript可以正确提示出组件中的方法和属性
}
}
复制代码
Vuex-class
Vuex-class是把Vuex和vue-class-component绑定到一起的一个包。目前还没有遇到问题,也就不做详解了。具体使用方式请查看文档。
上面就是目前在Vue项目中使用Typescript遇到的问题和注意点,其它问题待后续遇到后加以补充。