如何使用"tc39"装饰器将类定义转换为 Vue 3 组件定义?



tc39/proposal-decorators中使用的API与以前的decorators API非常不同。虽然TypeScript 5还不完全支持新的API,但是弃用以前的API是迟早的事,所以我将使用最新的API进行开发。

问题的答案是我们需要用装饰器把TypeScript类转换成什么来获得有效的Vue组件?对于旧的API是实际的,但现在需要用最新的API解决相同的问题。

初始代码为

import { defineComponent } from "vue";
/* [ Theory ] Overrides the eponymous type of "typescript/lib/lib.decorators.d.ts".
*  [ Reference ] https://github.com/tc39/proposal-decorators#classes */
type ClassDecorator = (value: Function, context: {
kind: "class";
name: string | undefined;
addInitializer: (initializer: () => void) => void;
}) => Function | void;

const VueComponentOptions: ClassDecorator = (targetClass: Function, context: ClassDecoratorContext): Function | void => {
// TODO check for the kind === "class"
const vueOptions: ComponentOptions = {
methods: {},
computed: {}
};
return defineComponent(vueOptions);
};

目前使用

/* https://stackoverflow.com/questions/75909821/the-classdecorator-type-defined-in-tc39-proposal-decorators-is-not-applicabl */
/* @ts-ignore TS1270 TS decorators are not fully TC39-compatible yet. */
@VueComponentOptions
export default class ReactiveStateExperimentalSample {
}

导致错误

ReactiveState-ExperimentalSample.vue?../../node_modules/ts-loader/index.js??clonedRuleSet-1!../../node_modules/vue-loader/dist/index.js??ruleSet%5B1%5D.rules%5B10%5D.use%5B0%5D:7
Uncaught TypeError: Function expected
... ```

原因是

如果返回函数以外的任何其他类型的值,则返回错误将被抛出。

https://github.com/tc39/proposal-decorators类

也许我需要包装defineComponent来发挥作用?

const VueComponentOptions: ClassDecorator = (targetClass: Function, context: ClassDecoratorContext): Function | void => {
const vueOptions: ComponentOptions = {
methods: {},
computed: {}
};
return (): ReturnType<typeof defineComponent> => defineComponent(vueOptions);
};

这次,没有JavaScript运行时错误,但是Vue会发出警告:

runtime-core.esm-bundler.js:170 [Vue warn]:无效的VNode类型:未定义(未定义)at at

,当然,组件不会被呈现。

我需要在VueComponentOptions中为最新的decorator API + Vue 3做些什么?

请不要推荐第三方库,因为这个问题关注的是实现。

  1. 您正在尝试:
    • 重新实现一个更新的vue-class-component的替代品:一个返回ReturnType<typeof defineComponent>的类,带有tc39装饰符

如果我理解错了,请纠正我。


<script lang="ts">
import { ComponentOptions, defineComponent } from 'vue';
import type { ComponentPublicInstance } from 'vue';
// vuepackagesruntime-coresrccomponent.ts
interface ClassComponent {
new (...args: any[]): ComponentPublicInstance
// here is where you put 
__vccOpts: ComponentOptions
}
// you need a class saying it implements ComponentPublicInstance for this.$props and other acessors
const Base = class Base {} as any as ClassComponent;

@(function VueComponentOptions(cls) { // inplace to see implecit typings
cls.__vccOpts = defineComponent({
name: cls.name,
// maybe like this or whatever way you want.
// ClassComponent used a lot of tricks here.
//   like co
data: () => new cls(),
props: ['msg'],
// whatever else you need
})
// return undefined
})
export default class MyComponent extends Base {
text = 'from class';
fn() {
this.text
this.$props; // has acess to all things in ComponentPublicInstance 
}
}
</script>
<template>
<h1>{{ msg }} {{ text }}</h1>
</template>

查看类似事情的实现以获取更多信息,https://github.com/facing-dev/vue-facing-decorator/blob/master/src/index.ts气密性好


如果你想同时使用@Ops class@Ops({...etc}) class,你需要一个(data: object) => ClassDecorator过载


编辑:我忘了__vccOpts,现在他们在这里

最新更新