Discover the seamless transformation of a class definition into a Vue 3 component definition utilizing the dazzling 'tc39' decorators

The proposed API in the tc39/proposal-decorators repository is significantly different from the previous decorators API. Although TypeScript 5 doesn't fully support the new API yet, it's only a matter of time before the old API becomes deprecated, so I'll proceed with using the newest API.

While the answer to the question "Into what do we need to convert the TypeScript class using decorators to get the valid Vue component?" is applicable to the old API, now we need to solve the same problem using the newest API.

Here's the initial code:

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);

};

Currently, when using this:

/* 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 {

}

I encounter the following error:

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
    ... (remaining text)

The cause of this is that if any value other than a function is returned, an error will be thrown.

You can do it by wrapping defineComponent inside a function:

const VueComponentOptions: ClassDecorator = (targetClass: Function, context: ClassDecoratorContext): Function | void => {

  const vueOptions: ComponentOptions = {
    methods: {},
    computed: {}
  };

  return (): ReturnType<typeof defineComponent> => defineComponent(vueOptions);

};

This time, there are no JavaScript runtime errors, but Vue emits the warning:

runtime-core.esm-bundler.js:170 [Vue warn]: Invalid VNode type: undefined (undefined) at at

As a result, the component will not be rendered. My question is, what should I do inside VueComponentOptions for the newest decorators API + Vue 3 case?

Please avoid recommending third-party libraries as my focus is on implementation.

Answer №1

  1. You are attempting to:
    • Develop a more recent alternative of vue-class-component: a class that returns
      ReturnType<typeof defineComponent>
      , using tc39 decorators

Please let me know if my understanding is incorrect.


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

Take a look at the implementation of something similar for more information, https://github.com/facing-dev/vue-facing-decorator/blob/master/src/index.ts#L29


If you wish to be able to use both @Ops class and @Ops({...etc}) class, you will require an

(data: object) => ClassDecorator
overload


Edit: An oversight on my part regarding __vccOpts. Here they are now

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React Native Component Error: Cannot read property '_this' of undefined

I am currently developing a face recognition application using React Native 0.63. I'm running my project using react-native run-android. However, I encountered an issue with Component Exception where it shows 'undefined is not an object (evaluati ...

The provided argument, which is of type 'RefObject<HTMLDivElement>', cannot be assigned to the parameter of type 'IDivPosition'

Currently, I am implementing Typescript with React. To organize my code, I've created a separate file for my custom function called DivPosition.tsx. In this setup, I am utilizing useRef to pass the reference of the div element to my function. However ...

What is the method to invoke a function within another function in Angular 9?

Illustration ` function1(){ ------- main function execution function2(){ ------child function execution } } ` I must invoke function2 in TypeScript ...

Automatically adjust div dimensions as window is resized

I am attempting to dynamically set a height in pixels for my container when its size changes. I have managed to display the size as text, which successfully updates when the container is resized. However, the height attribute on my container does not updat ...

Tips on sending various properties to makeStyles() using TypeScript

After learning how to pass 1 prop to makeStyle() from a resource, I decided to try passing in 2 props for my project. However, I encountered an error stating cannot find name 'props'. Any assistance on this issue would be greatly appreciated! con ...

What could be causing my code to not run after subscribing to the observables?

In my code, I have two methods that return two lists: one for accepted users and the other for favorite users. The first part of my code works well and returns both lists, but in the second part, I need to filter out the accepted users who are also on the ...

What is the procedure for entering the output generated by genMockFromModule when creating a custom mock in Jest?

Looking at my orders directory structure, I have a function in the orders/helpers file that I want to test using a manual Jest mock. orders __mocks__ helpers.ts __tests__ orders.ts helpers.ts orders.ts The orders/helpers.ts file contains ...

Creating a Dynamic Clear Button for a Text Area in Angular

Working on my Angular application, I have implemented a form with a textarea element. My goal is to incorporate a clear button inside the textarea element that should: Appear only when the textarea is focused Disappear when the textarea is out of focus ( ...

Finding Nested Key Paths in TypeScript for Objects and Arrays

I am in search of a unique method to create a TypeScript type that can take an object type and retrieve all the nested key paths, including properties within arrays as well. I want to exclude any default array properties such as "push" or "pop." While I ha ...

Typescript - unexpected behavior when using imported JavaScript types:

I am struggling with headaches trying to integrate an automatically generated JavaScript library into TypeScript... I have packaged the JavaScript library and d.ts file into an npm package, installed the npm package, and the typings modules in the TypeScr ...

Tips for passing TouchableOpacity props to parent component in React Native

I created a child component with a TouchableOpacity element, and I am trying to pass props like disabled to the parent component. Child component code: import React from 'react'; import {TouchableOpacity, TouchableOpacityProps} from 'react- ...

Decoding the HTML5 <video> tag using the html-react-parser library

I'm working on a NextJS V13 app where I need to display HTML content fetched from a CMS. Instead of using dangerouslySetHtml, I opted for the html-react-parser package to parse the HTML and replace certain embedded tags like <a>, <img>, an ...

AngularJS2 brings a powerful and seamless implementation of indexedDB for efficient

I'm on the hunt for an indexeddb implementation that works seamlessly with Angularjs2. While I stumbled upon this api at https://github.com/gilf/angular2-indexeddb, it appears to be lacking in active development and may not be ready for production use ...

Obtaining images from the backend within a component's TypeScript file in a MEAN stack application is a

In my component.ts file, I am looking to retrieve images from the backend/images folder as Image objects. The paths of these images are stored in the database. this.productsService.getProduct(this.editId).subscribe(productData => { this.name = prod ...

Troubleshooting Next.js and Tailwind CSS Breakpoints: What's causing the

Having trouble with my custom breakpoints. For instance, I attempted the following: <div className="flex flex-row gap-5 mb-5 md:ml-15 sm:ml-15"> ... </div> The margin is not being applied on small and medium screens. Here are the th ...

Issues with Formik sign-up

Working on a study project involving React, Typescript, Formik, and Firebase presents a challenge as the code is not functioning correctly. While authentication works well with user creation in Firebase, issues exist with redirection, form clearing, and da ...

Guide on invoking personalized server-side functions (such as object parsing) utilizing Typescript and Angular tools

I've been grappling for weeks to make custom service calls function with Typescript / Angular / C#. It's been a challenge to find a workable solution online, and the more I search, the more bewildered I become. My current approach has largely be ...

Ensuring the proper export of global.d.ts in an npm package

I'm looking to release a typescript npm package with embedded types, and my file structure is set up like so dist/ [...see below] src/ global.d.ts index.ts otherfile.ts test/ examples/ To illustrate, the global.d.ts file contains typings ...

Encountered an issue with locating the module 'webpack-cli/bin/config-yargs' while attempting to run webpack-dev

Encountering an error while trying to start the webpack dev server with the command provided below. Despite suggestions that it could be due to outdated webpack versions, I am confident that all components are up to date: [email protected] [email ...

Is it necessary for TypeScript classes that are intended for use by other classes to be explicitly exported and imported?

Is it necessary to explicitly export and import all classes intended for use by other classes? After upgrading my project from Angular 8 to Angular 10, I encountered errors that were not present before. These issues may be attributed to poor design or a m ...