API, предназначенный для tc39/proposal-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 ... ```
Причина в
Если возвращается любой другой тип значения, кроме функции, возникает ошибка будет брошен.
Может быть, мне нужно обернуть 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]: неверный тип VNode: undefined (не определено) в at
и, конечно же, компонент не будет отображаться.
Что мне нужно сделать внутри VueComponentOptions
для новейшего корпуса декораторов API + Vue 3?
Пожалуйста, не рекомендуйте сторонние библиотеки, потому что этот вопрос сосредоточен на реализации.
ReturnType<typeof defineComponent>
, с декораторами tc39.Пожалуйста, поправьте меня, если я неправильно понял.
<script lang = "ts">
import { ComponentOptions, defineComponent } from 'vue';
import type { ComponentPublicInstance } from 'vue';
// vue\packages\runtime-core\src\component.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#L29
Если вы хотите использовать как @Ops class
, так и @Ops({...etc}) class
, вам понадобится перегрузка (data: object) => ClassDecorator
.
редактировать: я забыл о __vccOpts
, вот они сейчас
Вам за обновленный ответ. "Пожалуйста, поправьте меня..." - это близко, однако я хочу изменить некоторые API. Если мы вернем defineComponent()
, будет выдана ошибка Uncaught TypeError: Function expected
.
@TakeshiTokugawaYD отредактировано. ClassComponent использует __vccOpts
статическую опору
Теперь работает нормально! Спасибо за поддержку вашего решения.
пожалуйста, сделайте MRE на stackblitz (т. е. один компонент с package.json, в котором перечислены точные версии зависимостей (так как есть class-dec @ 7 и @ 8, prop-dec и т. д.))