Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

An type error occurs when building Teleport using the <script setup lang="ts"> #2855

Closed
Wizard67 opened this issue Dec 21, 2020 · 15 comments · Fixed by #5458
Closed

An type error occurs when building Teleport using the <script setup lang="ts"> #2855

Wizard67 opened this issue Dec 21, 2020 · 15 comments · Fixed by #5458
Labels
has workaround A workaround has been found to avoid the problem 🐞 bug Something isn't working scope: teleport scope: types

Comments

@Wizard67
Copy link

Version

3.0.4

Reproduction link

https://github.com/Wizard67/rollup-vue

Steps to reproduce

  1. install dependencies.
  2. run build script.

What is expected?

Building Success.

What is actually happening?

typescript throws the following error.

semantic error TS2345: Argument of type '{ new (): { $props: VNodeProps & TeleportProps; }; __isTeleport: true; }' is not assignable to parameter of type 'string | ComponentOptions<any, any, any, Record<string, ComputedGetter<any> | WritableComputedOptions<any>>, MethodOptions, any, any, any> | ... 9 more ... | ClassComponent'.
  Type '{ new (): { $props: VNodeProps & TeleportProps; }; __isTeleport: true; }' is not assignable to type 'ComponentPublicInstanceConstructor<any, any, any, any, Record<string, ComputedGetter<any> | WritableComputedOptions<any>>, MethodOptions>'.
    Types of property '__isTeleport' are incompatible.
      Type 'true' is not assignable to type 'never'.

It looks like the incompatibility between the createBlock and Teleport types is the cause of the.

@LinusBorg
Copy link
Member

createBlock() accepts the following types as its first argument:

export type VNodeTypes =
  | string
  | VNode
  | Component
  | typeof Text
  | typeof Static
  | typeof Comment
  | typeof Fragment
  | typeof TeleportImpl
  | typeof SuspenseImpl

Those *Impl types ares used internally only though. Externally, these implementations are cast to soemthing different - typeof Teleport != TeleportImpl.

First instinct is that we should use Teleport and Suspense here as well, instead of their internal *Impl counterparts.

This isn't a problem when not using script setup as the created render function never runs through the typescript compiler in these cases. In other words: a normal component creates the same render function, and at runtime it works - but only with script setup this is actually catched by the TS compiler.

@LinusBorg
Copy link
Member

Workaround:

<script lang="ts" setup>
import { 
  Teleport as teleport_,
  TeleportProps,
  VNodeProps
} from 'vue'

const Teleport = teleport_ as {
  new (): {
    $props: VNodeProps & TeleportProps
  }
}
</script>
<template>
  <component :is="Teleport">

  </component>
</template>

@LinusBorg LinusBorg added the has workaround A workaround has been found to avoid the problem label Jan 27, 2021
@LinusBorg LinusBorg removed their assignment Mar 9, 2021
@josh-berry
Copy link

Hitting this or a very similar issue in my vue-loader/webpack-based project even without <script setup> / with an explicit defineComponent call in my <script lang="ts"> section. The issue just started after a recent update to vue-loader (which now apparently sends template code through the TypeScript compiler).

Thanks for sharing the workaround, it seems to work in my case as well.

@canidas
Copy link

canidas commented Nov 22, 2021

Same problem with Vue 3.2.22 SFC + <script lang="ts"> + defineComponent in a webpack project:

TS2345: Argument of type '{ new (): { $props: VNodeProps & TeleportProps; }; __isTeleport: true; }' is not assignable to parmeter of type 'VNodeTypes | ClassComponent'.
    Type '{ new (): { $props: VNodeProps & TeleportProps; }; __isTeleport: true; }' is not assignable to type 'ComponentPublicInstaneConstructor<any, any, any, any, ComputedOptions, MethodOptions>'.
      Types of property '__isTeleport' are incompatible.
        Type 'true' is not assignable to type 'undefined'.

Workaround works, thanks.

@Yendric
Copy link

Yendric commented Feb 18, 2022

This bug still occurs when using the latest version of vue.

@LinusBorg
Copy link
Member

Also indicated by the fact that the issue is still open, yes.

LinusBorg added a commit that referenced this issue Feb 19, 2022
… types

not their internal counterparts (TeleportImpl and SupenseImpl)

fix: #2855
@mrleblanc101
Copy link

We also had to do the same for Suspense.

<template>
    <component :is="Suspense">
    </component>
</template>

<script lang="ts">
import {Suspense as suspense_, VNodeProps, SuspenseProps} from 'vue';

export default defineComponent({
    name: 'App',
    setup() {
        const Suspense = suspense_ as {
            new (): {
                $props: VNodeProps & SuspenseProps
            }
        }

        return {
            Suspense,
        }
    },
});
</script>

@Yendric
Copy link

Yendric commented Mar 30, 2022

Suspense has also been added to the VNodeTypes type in LinusBorg's PR.

@mrleblanc101
Copy link

I was adding the workaround for people that have the issue with Suspense as the workaround was not in the thread and there doesn't seem to be a separate issue for that.

@codebakery-ch
Copy link

codebakery-ch commented Jun 9, 2022

I just came across this when doing watch with webpack. Maybe it helps somebody or is related to this.

I get the error when I have my <template> like this:

<template>
  <div>
    <Teleport to="body">
      <transition name="fade">
        <div>...</div>
      </transition>
    </Teleport>
  </div>
</template>

When I remove the leading <div>, the Error disappears

<template>
    <Teleport to="body">
      <transition name="fade">
        <div>...</div>
      </transition>
    </Teleport>
</template>

But it's not consistent... It seems the error only appears the first time, then after a change it seems to disappear.

If I add or remove the leading div while watch is running, the type error always disappears.
If I have no leading div, the error appears on the second watch run, not the first.

Additionaly, if I remove the leading div, I get a Vue Warning: "Extraneous non-props attributes (name) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. " (which probably makes sense, but still, maybe it helps)

Feel free to delete this comment if it is off topic.

@ThaDaVos
Copy link

I just came across this when doing watch with webpack. Maybe it helps somebody or is related to this.

I get the error when I have my <template> like this:

<template>
  <div>
    <Teleport to="body">
      <transition name="fade">
        <div>...</div>
      </transition>
    </Teleport>
  </div>
</template>

When I remove the leading <div>, the Error disappears

<template>
    <Teleport to="body">
      <transition name="fade">
        <div>...</div>
      </transition>
    </Teleport>
</template>

But it's not consistent... It seems the error only appears the first time, then after a change it seems to disappear.

If I add or remove the leading div while watch is running, the type error always disappears. If I have no leading div, the error appears on the second watch run, not the first.

Additionaly, if I remove the leading div, I get a Vue Warning: "Extraneous non-props attributes (name) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. " (which probably makes sense, but still, maybe it helps)

Feel free to delete this comment if it is off topic.

I am having the same issue - but sadly your solution doesn't fix it for me - I am running in a Laravel Mix stack (which I converted to Typescript) and I am only seeing this error when running a production build - dev builds don't throw the error

@codebakery-ch
Copy link

codebakery-ch commented Jun 13, 2022

...I am only seeing this error when running a production build - dev builds don't throw the error

for me it's the opposite 🤷‍♂️ runs fine on prod build, only watch and dev complain...

@JamesManningR
Copy link

...I am only seeing this error when running a production build - dev builds don't throw the error

for me it's the opposite 🤷‍♂️ runs fine on prod build, only watch and dev complain...

I also get it only in the production build 🤷‍♂️ weird

@DariaTsypkina
Copy link

I've also met with this issue building project for production. Workaround helped.

@glspdotnet
Copy link

Additionaly, if I remove the leading div, I get a Vue Warning: "Extraneous non-props attributes (name) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. " (which probably makes sense, but still, maybe it helps)

I can't speak to the dev/prod build issue, but with regard to the attribute inheritance, you can solve that issue by explicitly binding the Teleport props to the dynamic component. I'm currently using the following as a generalized Teleport replacement (thanks @LinusBorg for the head start!):

<!-- VueTeleport.vue -->

<template>
    <component :is="Teleport" v-bind="props">
        <slot></slot>
    </component>
</template>

<script setup lang="ts">
import { Teleport as teleport_, type TeleportProps, type VNodeProps } from 'vue';

const Teleport = teleport_ as {
    new (): {
        $props: VNodeProps & TeleportProps
    }
};

const props = defineProps<{
    to: TeleportProps['to'],
    disabled?: TeleportProps['disabled'],
}>();
</script>

Note that if the Teleport API changes then any changes would also need to be propagated to the props definition here. Hopefully this issue will be solved before that even becomes an problem, though, lol. Also, FWIW, I haven't had a need for non-prop attributes to be further inherited (via v-bind="$attrs" on the <slot> or a wrapper <div>, for instance), since they'd likely just be passed in directly with the slotted content. I can't say how the built-in Teleport component behaves in this regard as I've completely replaced my usage of it with this component. Hope this helps someone!

lolamtisch added a commit to MALSync/MALSync that referenced this issue Aug 31, 2022
LinusBorg added a commit that referenced this issue Oct 20, 2022
… types (fix: #2855) (#5458)

Co-authored-by: Carlos Rodrigues <carlos@hypermob.co.uk>
chrislone pushed a commit to chrislone/core that referenced this issue Feb 4, 2023
… types (fix: vuejs#2855) (vuejs#5458)

Co-authored-by: Carlos Rodrigues <carlos@hypermob.co.uk>
zhangzhonghe pushed a commit to zhangzhonghe/core that referenced this issue Apr 12, 2023
… types (fix: vuejs#2855) (vuejs#5458)

Co-authored-by: Carlos Rodrigues <carlos@hypermob.co.uk>
@github-actions github-actions bot locked and limited conversation to collaborators Sep 20, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
has workaround A workaround has been found to avoid the problem 🐞 bug Something isn't working scope: teleport scope: types
Projects
None yet