Ways to enhance the type definitions for a built-in HTML element in Vue.js?

Imagine having an element that wraps around an input and inherits all of its properties, along with some extras.

In React, you would define this as:

interface ExtendedInputProps extends React.ComponentPropsWithoutRef<'input'> {
    some: Type
}

This scenario is quite common. In Vue 3, prop types are generated based on what is passed to the props: object in defineComponent.

It's like envisioning something similar to:

props:{
    ...getComponentProps('input')
    additionalProp: String
}

However, figuring out how to achieve this and finding documentation on it seems challenging. Is it possible?

Answer №1

In the simplest scenario, if the input serves as the root element of the component, there is no need to declare any additional settings. You can simply pass attributes to your component and they will automatically cascade down.

//NumberInput Component
<template>
    <input :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"  />
</template>

<script setup lang="ts">
defineEmits(["update:modelValue"])
const props = withDefaults(defineProps<{
    modelValue?: number
}>(), { modelValue: 0 })
</script>

Usage example:

<number-input v-model="data" type="text" placeholder="123-45-678" />

In this case, the type and placeholder attributes will be directly applied to the input element.

If the input is nested within the component, attribute inheritance needs to be disabled:

//NumberInput Component
<template>
  <div class="wrapper">
    <input :value="modelValue" v-bind="$attrs" 
      @input="$emit('update:modelValue', $event.target.value)"  />
  </div>

</template>

<script setup lang="ts">
defineEmits(["update:modelValue"])
const props = withDefaults(defineProps<{
    modelValue?: number
}>(), { modelValue: 0 })
</script>

<script lang="ts">
// normal `<script>`, executed in module scope (only once)
// declare additional options
export default {
  inheritAttrs: false,
  customOptions: {}
}
</script>

It's important to note that a second script tag has been added to turn off inheritAttrs and include v-bind="$attrs" for explicit attribute passing. For further details on this topic, refer to this resource.

Answer №2

If we are looking for the closest writing, it might be:

<template>
  <input />
</template>

<script lang="ts" setup>
import type { InputHTMLAttributes } from 'vue'

// by explicitly defining props, TypeScript support is improved
interface MyInputProps extends /* @vue-ignore */ InputHTMLAttributes {
  some?: Type
}

defineProps<MyInputProps>()
</script>

Now, Typescript should recognize that bindings can be applied to <input /> within the component.

<template>
  <MyInput :value="'typescript now recognizes the value attribute!'" />
</template>

This solution has been tested and works well with my

<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2670534366150812081e">[email protected]</a>
.

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

I can't seem to understand why I am receiving an undefined property when trying to access an

While working with typescript and react within a project created using create-react-app, I encountered an issue during runtime: Cannot read property 'Customer' of undefined. This error occurred while utilizing the following module imports: impor ...

In Angular, you can easily modify and refresh an array item that is sourced from a JSON file by following these steps

Currently, I am working on implementing an edit functionality that will update the object by adding new data and deleting the old data upon updating. Specifically, I am focusing on editing and updating only the comments$. Although I am able to retrieve th ...

Creating a regular expression for validating phone numbers with a designated country code

Trying to create a regular expression for a specific country code and phone number format. const regexCountryCode = new RegExp('^\\+(48)[0-9]{9}$'); console.log( regexCountryCode.test(String(+48124223232)) ); My goal is to va ...

Combining objects using Vue.js and Axios

After fetching data from an axios request and a fetch call to an RSS feed, I have two objects with fields that serve the same purpose but have different names. See the example below: Two Object The objects currently look like this: Obj1 = {title: "Main te ...

Executing a series of HTTP requests sequentially using Angular 5

I need some guidance on sending an array of HTTP requests in sequential order within my application. Here are the details: Application Entities : Location - an entity with attributes: FanZone fanZone, and List<LocationAdministrator> locationAdmins ...

Is it possible to transfer the setState function between different contextProviders?

I'm encountering difficulties in setting a state when passing the context provider to other elements. Here is my code snippet. I have created a FancyboxContext so that I can easily access it from anywhere in the app. import React, { createContext, use ...

Ways to ensure your component is updated when there are changes to the props in N

I need to update the data every time there is a change in props within the component, and I want to display it without having to reload the page. pages/invoice/index.vue: <template> <div> <b-table-column field="InvoiceNo" ...

Debugging TypeScript on a Linux environment

Approximately one year ago, there was a discussion regarding this. I am curious to know the current situation in terms of coding and debugging TypeScript on Linux. The Atom TypeScript plugin appears promising, but I have not come across any information ab ...

Leveraging an external JSON file within a Vue application

A friend of mine isn't very tech-savvy, so I'm building a website for him with an idea to simplify the process. I plan to create a JSON file to store all the text and image paths, allowing him to easily make changes without needing to delve into ...

Dealing with models in Vue.js is proving to be quite a challenge

Why isn't myGame showing as 超級馬力歐 initially and changing when the button is pressed? It just displays {{myGame}} instead. I'm not sure how to fix it, thank you! let myApp = new vue({ el:'myApp', data:{ myGame:&a ...

Building a database using a dump.sql file in NodeJS (Express) with the added power of TypeScript

I am currently building an application using Express and TypeScript. While the app is already configured to work with MySQL, I am facing a challenge in figuring out how to create the database based on a dump.sql file. CREATE DATABASE IF NOT EXISTS test; U ...

Updating array values using radio buttons in Angular: A step-by-step guide

I am creating an array of phone objects where each phone is assigned a role, either main or secondary. I want to be able to update the main phone using a radio button and have it reflect in my object list. Here is my code: HTML <section *ngFor="le ...

The test suite encountered an error: Invariant violation occurred because the statement "Buffer.from("") instanceof Uint8Array" was evaluated as false when it should have been

**Error: The condition "Buffer.from("") instanceof Uint8Array" is incorrectly evaluating to false This error indicates a problem with your JavaScript environment. eBuild relies on this specific condition which suggests that your JS environment is not funct ...

Assignment on Ionic's Cascading Style Sheets classes

As I work on styling my app, I find myself struggling with the extra CSS classes that are added when I preview the source in a running app. It's particularly confusing when all I want to do is change the menu header background. In my app.html file, I ...

The VueJS Chosen directive fails to refresh when new options are selected

Struggling to populate my jQuery Chosen dropdown field with AJAX data using VueJS. Unfortunately, when trying to update the values, the Chosen dropdown does not reflect the changes. I've experimented with different approaches, including manually trig ...

Utilizing multiple sticky columns in BootstrapVue with Vue.js

I am facing an issue with multiple sticky columns in my layout. When these columns are set as sticky, they tend to visually stack over each other, sometimes causing the left-most sticky column to "peek" out from under the next one. Is there a way to add m ...

The function cannot be invoked. The 'Boolean' type does not have any call signatures. An error has occurred in the computed property of Vue3

Currently, I am working on creating a computed property that checks if an item is in the array. The function I have created returns a boolean value and takes one parameter, which is the item to be checked. isSelected: function (item: MediaGalleryItemTypes) ...

Exploring the magic of Plugins within Vue's Single File Components

One of my recent projects involved writing a custom plugin in Vue: var MyCoolVuePlugin = { install(Vue) { Vue.prototype.doStuff = function() { console.log("I'm a useless plugin") } } } export default MyCoolVuePlug ...

How can a component be rendered outside Vuejs's default router-view?

I've created a Vue app that utilizes vue-router for navigation. My app.vue file is quite simple: <template> <div id="app"> <main-header/> <router-view/> </div> </template> <script>...</script ...

Error message: ParseError: Received an unexpected character '<' while running tests using AVA

Initially encountering an issue within the project built on nuxt, I attempted to resolve it by creating a new project using vue-cli and re-installing AVA via npm. However, this did not have any effect on the problem at hand. Upon researching, I came across ...