依赖
dependencies
vue-class-component
vue-property-decorator
vue-tsx-support
vuex-class
vue-tsx-support
是用来增强 Vue
的 Props
、Event
等类型的
不使用 vue-tsx-support
class Demo extends Vue {
@Prop() demo: string
}
在外部是无法感知这个 props
类型的
使用 vue-tsx-support
interface Props {
demo: string
}
class Demo extends tsx.Component<Props> implements Props {
@Prop() demo: string
}
这种写法外部是可以感知需要传入的 Props
的类型的
devDependencies
@typescript-eslint/eslint-plugin
@typescript-eslint/parser
@vue/eslint-config-typescript
eslint-plugin-import
eslint-plugin-typescript
ts-loader
typescript
还有一些 @types 需要添加可自行查找(缺什么 types 会报错提示)
eslint
eslint 中需要添加对 ts、tsx 的支持,同时在迁移的过程中还会存在 js 和 vue 主要这两个地方需要注意(添加对 ts 的支持)
plugins: [ 'typescript', '@typescript-eslint' ],
parserOptions: { parser: "@typescript-eslint/parser", "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module", }
同时需要在你的 workspace 的 vscode setttings.json 中增加对 ts 和 tsx 的验证
"typescript.tsdk": "node_modules/typescript/lib",
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "typescript",
"autoFix": true
},
{
"language": "typescriptreact",
"autoFix": true
}
],
"eslint.options": { //指定vscode的eslint所处理的文件的后缀 "extensions": [ ".js", ".ts", ".tsx", ".vue" ] }
同时存在 vue 和 jsx
在我们改造过程中不可避免的会遇到在写 jsx 的时候会应用到之前的一些 vue 的组件,而这些组件有没有被全局 install,这个时候我们可以先如下处理
@Component({
components: {
DemoVue,
},
})
class Demo extends Vue {
render() {
return (<demo-vue />)
}
}
对于 template 中的一些修饰符,我们在 jsx 中该怎么处理,比 xxx.sync 修饰符,sync 只是一个语法糖,我们可以在组件的 on 中进行监听,如下
@Component({
components: {
DemoVue,
},
})
class Demo extends Vue {
render() {
return (<demo-vue on={{'update:Click': () => {}}} />)
}
}
同时我们需要区分 attrs 和 props , props 可以直接在组件上进行传递,attrs 需要放到 attrs 属性下,如下
@Component({
components: {
DemoVue,
},
})
class Demo extends Vue {
render() {
return (<demo-vue on={{'update:Click': () => {}}} propsA attrs={{attrsA: 'xxx'}} />)
}
}
对于一些第三方库没有 decorator ,该怎么办,我们可以借助 vue-class-component 中的 createDecorator 来造一个简易的轮子,如下 apollo 和 metaInfo
export function ApolloDes() {
return function(_t: Vue, key: string, desc: any) {
createDecorator(options => {
options.apollo = desc.value()
})(_t, key)
}
}
export function MetaInfoDes() {
return function (_target: Vue, key: string, desc: any) {
createDecorator((options) => {
options.metaInfo = desc.value
})(_target, key)
}
}
使用方式
class Demo extends Vue {
@MetaInfoDes()
metaInfo() {
return {
title: 'xxx',
}
}
@ApolloDes
apollo() {
return {
reqA: {
query: xxxx
}
}
}
render() {
return (<demo-vue on={{'update:Click': () => {}}} propsA attrs={{attrsA: 'xxx'}} />)
}
}
一些·奇怪的 bug
如下例
class Demo extends Vue {
test = {name: 'xxx'}
render() {
const { test } = this
return (
<test props={test}/>
)
}
}
上述代码会在编译的运行的时候将组件 test 编译为 <xxxx />
,理解之后也不奇怪,因为 test 也是一个变量,只不过 这个组件被全局注册我们没在这 应用,刚好组件和变量 test 重名,而且 test 变量具有 name 属性,运行时,test 的 name 就会被编译成组件名了,组件和 test 都是变量,只不过组件这个变量在 Vue 中被全局注册了,而且这个组件名也是小写,lint 工具不会去检查,就造成了一种错觉。