Как превратить определение класса в определение компонента Vue 3 с помощью декораторов «tc39»?

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
    ... ```

Причина в

Если возвращается любой другой тип значения, кроме функции, возникает ошибка будет брошен.

https://github.com/tc39/proposal-decorators#classes

Может быть, мне нужно обернуть 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?

Пожалуйста, не рекомендуйте сторонние библиотеки, потому что этот вопрос сосредоточен на реализации.

пожалуйста, сделайте MRE на stackblitz (т. е. один компонент с package.json, в котором перечислены точные версии зависимостей (так как есть class-dec @ 7 и @ 8, prop-dec и т. д.))

Dimava 10.04.2023 18:06
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
1
160
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
  1. Вы пытаетесь:
    • Повторно реализовать более новую альтернативу vue-class-component: класс, который возвращает 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.

Takeshi Tokugawa YD 15.04.2023 05:35

@TakeshiTokugawaYD отредактировано. ClassComponent использует __vccOpts статическую опору

Dimava 15.04.2023 11:56

Теперь работает нормально! Спасибо за поддержку вашего решения.

Takeshi Tokugawa YD 16.04.2023 05:04

Другие вопросы по теме