Subscribe on changes!

Typescript issue with importing type from vue

avatar
Jul 11th 2023

Vue version

3.3.4

Link to minimal reproduction

https://github.com/tragid/vue-default-export-error

Steps to reproduce

I'm trying to build a Button component using Typescript and utilizing types of HTML element imported from Vue package. Here is the code:

import type { ButtonHTMLAttributes, LinkHTMLAttributes } from 'vue'
import type { RouterLinkProps } from 'vue-router'

type ButtonOrAnchorProps = BaseProps & ButtonHTMLAttributes & LinkHTMLAttributes
type ButtonAsRouterLink = BaseProps & RouterLinkProps & LinkHTMLAttributes
type ButtonProps = ButtonAsRouterLink | ButtonOrAnchorProps

const props = defineProps<ButtonProps>()

What is expected?

The type should be imported normally without any error.

What is actually happening?

Vue throws error:

[@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

It's kind of strange because I can still access the attributes from props variable like props.href but the app is not running.

What I tried is to create alternative types that extend ButtonHTMLAttributes and LinkHTMLAttributes, it's like:

import { type ButtonHTMLAttributes, type LinkHTMLAttributes } from 'vue'

export interface BtnHTMLAttr extends /* @vue-ignore */ ButtonHTMLAttributes {}

export interface LinkHTMLAttr extends /* @vue-ignore */ LinkHTMLAttributes {}

The import error is gone but the app is still not functioning properly. When I add a href prop to the component, seems like the component doesn't recognize href prop

System Info

No response

Any additional comments?

No response

avatar
Jul 20th 2023

#8522

avatar
Jul 20th 2023

Hi, thanks for your reply.

For some reasons, I cannot get the href props even if I pass it in parent component. Here is my code for Button component:

<script setup lang="ts">
import clsx from 'clsx'
import type { ButtonHTMLAttributes, LinkHTMLAttributes } from 'vue'

// Here is tailwind class for variants
const variants = {
  primary: 'bg-blue-600 text-white hover:bg-gray-50:text-blue-600',
  secondary: 'bg-gray-200 text-black-300 hover:bg-blue-600:text-white'
}

interface BaseProps {
  variant?: keyof typeof variants
}

interface ButtonAsButton
  extends /* @vue-ignore */ BaseProps,
    /* @vue-ignore */ ButtonHTMLAttributes {}
interface ButtonAsLink extends /* @vue-ignore */ BaseProps, /* @vue-ignore */ LinkHTMLAttributes {}
type ButtonProps = ButtonAsButton | ButtonAsLink

const props = withDefaults(defineProps<ButtonProps>(), {
  variant: 'primary'
})

// Here you can add style from tailwind, below is the demo
const className = clsx(
  'flex items-center justify-center px-4 py-2 rounded font-medium focus:outline-none',
  variants[props.variant],
  props.class
)

const newProps = { ...props }

newProps.class = className
let As = 'button'
if ('href' in newProps) {
  As = 'a'
}
if (As === 'button') {
  newProps['type'] = newProps.type ? newProps.type : 'button'
}
</script>
<template>
  <As v-bind="newProps"><slot></slot></As>
</template>

<style scoped></style>

And I pass the href prop like: <VButton href="dsadsad">fdss</VButton>

However, href isn't recognized. What is the problem?

avatar
Jul 20th 2023

Ah! I didn't look carefully, but currently, I have separated Button and Link into two separate components.