ezolenko / rollup-plugin-typescript2

Rollup plugin for typescript with compiler errors.
MIT License
822 stars 71 forks source link

Error `TS2322` using Vue's dynamically named Slots #325

Closed Shenor closed 2 years ago

Shenor commented 2 years ago

What happens and why it is wrong

When assembling a project with dynamic slots, the following error appears: image

[!] (plugin rpt2) Error: C:/Users/p.marusov/Desktop/element-ui/src/components/ElTable/ElTable.vue?vue&type=script&setup=true&lang.ts(227,7): semantic error TS2322: Type 'Function' is not assignable to type 'Slot'.
  Type 'Function' provides no match for the signature '(...args: any[]): VNode<RendererNode, RendererElement, { [key: string]: any; }>[]'.

The problem arises specifically because of this code. In its absence, the assembly is successful:

      <template v-for="(_, slot) in $slots" :key="_" #[slot]="scope">
        <slot :name="slot" v-bind="scope || {}" />
      </template>

rollup.config.js

:
```js export default [ { input: "src/index.ts", output: [ { format: "esm", file: "dist/index.mjs", exports: "named", }, { format: "cjs", file: "dist/index.js", exports: "named", }, ], external: ["vue", "quasar"], plugins: [ del({ targets: "dist" }), peerDepsExternal(), nodeResolve(), vue(), typescript2({ clean: true, typescript: ttypescript, tsconfig: "tsconfig.rollup.json", }), babel({ babelHelpers: "runtime" }), commonjs(), postcss(), image(), terser(), ], }, ]; ```

tsconfig.json

:
```js { "compilerOptions": { "target": "esnext", "module": "esnext", "declaration": true, "removeComments": true, "moduleResolution": "node", "isolatedModules": true, "noImplicitAny": false, "sourceMap": true, "baseUrl": ".", "paths": { "@/*": ["src/*"] }, "plugins": [ { "transform": "@zerollup/ts-transform-paths", "exclude": [ "*" ] } ] }, "files": [ "src/index.ts", "src/shims-vue.d.ts" ], "exclude": ["node_modules"] } ```

I tried to set the type of slots, but all to no avail.

 <template v-for="(_, slot) in ($slots as {})" :key="_" #[slot]="scope">
      <slot :name="slot" v-bind="scope || {}" />
    </template>

or

 <template v-for="(_, slot) in ($slots as Slots)" :key="_" #[slot]="scope">
      <slot :name="slot" v-bind="scope || {}" />
  </template>
<script lang="ts">
  import { Slots } from "vue";
</script>

I don't understand how this can be fixed.

agilgur5 commented 2 years ago

I had to look up what Slots were as I'm not too familiar with Vue, seems like these are the equivalent of React's children props (except a good bit more complex, enough so that the docs have React JSX-like pseudo-code to explain it; thought Vue was supposed to be simpler and less Angular-y?)

Slots type coercion

$slots as {} $slots as Slots

You can try $slots as any if you're trying to coerce the types, though I'm not sure if v-for even supports TS?

What does vue-tsc output?

It's possible the type-error is correct, what does vue-tsc output for this code? This plugin just runs a TypeScript LanguageService on the resulting code, so generally it is supposed to have the same output as tsc as they both use the same TS API (+/- some Rollup semantics and config). This is a two-step compile though as it's a Vue SFC, so vue-tsc probably makes sense to check against.

It's quite difficult to tell what the issue is here given that this isn't raw TS (and hence not a minimal reproduction either) and it's using a handful of Vue-specific features at once on top of that.

Can also try check: false as a workaround

Another workaround you can do is to set check: false in this plugin's options to disable type-checking entirely and get the compilation to pass at least (and type-check with vue-tsc instead, for example).

Shenor commented 2 years ago

vue-tsc did not give results. It doesn't output anything about dynamic slots. Disabling verification check: false is the only solution so far, but not the one that I would like. Thank you for the answer, I will continue to understand

agilgur5 commented 2 years ago

@Shenor do you have a (minimal) reproduction of this issue?

I've been meticulously going through all the issues and doing root cause analyses and fixing most of them, but I can't really investigate this further without a reproduction.

agilgur5 commented 2 years ago

@Shenor I created a minimal repro here and was unable to reproduce the error you received. rpt2 does not throw any error and neither does vue-tsc.

It's possible that there's something missing in my reproduction, but given the lack of details here, this is all I was able to come up with.

Without more input from you, there's nothing more that we can do here, and given the current inability to reproduce, it doesn't seem like this is an error within rpt2 either, but rather something in your environment, at least as far as I can tell given the current repro I created.

agilgur5 commented 2 years ago

Closing this as stale as OP has not responded in nearly a month and a reproduction has been unsuccessful.

Can re-open if a minimal repro is provided.

tiagoskaneta commented 2 years ago

the issue I have is somewhat related. but it occurs when actually using a conditional template. I forked @agilgur5 repo here.

in essence, by doing:

<my-component>
    <template v-if="true" #foo> Bar </template>
  </my-component>

This is being transpiled to:

function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_my_component = resolveComponent("my-component");

  return (openBlock(), createBlock(_component_my_component, null, createSlots({ _: 2 /* DYNAMIC */ }, [
    {
          name: "foo",
          fn: withCtx(() => [
            _hoisted_1
          ])
        }

  ]), 1024 /* DYNAMIC_SLOTS */))
}

Where I get the following error: image

Not really sure the issue is on rpt2 or on vue side, as it seems the transpiled/generated code doesn't match the interface of createSlots in this case.

For the record, I can get away with it by declaring something like this:

// types/vue.d.ts
import 'vue'
declare module 'vue' {
  function createSlots(
    slots: Record<string, any>,
    dynamicSlots: (any | any[] | undefined)[]
  ): Record<string, any>
}

Which is fine for my case as I never call the createSlots function directly, so the loss of proper type checking on it is okay.

agilgur5 commented 1 year ago

@tiagoskaneta thanks for providing a detailed example and repro!

That definitely looks like a problem on the rollup-plugin-vue side, as it generates the render function (and not rpt2).

rollup-plugin-vue is no longer maintained though, so it's possible the typings are fixed in newer versions of the Vue compiler. Though I see the peerDep is just *, so it should use the same version of Vue as you have in your deps 🤔

So either there's some wrapper code that rollup-plugin-vue generates that's out-of-date, or this is still a bug in the Vue compiler's typings for SFCs

d0peCode commented 1 year ago

This issue still occure when I try to add v-if on my template:

<template #error v-if="errors.length">

With the newest version of Vue. It happens only when building for prod. typescript check doesn't see any issue

michaelcozzolino commented 1 year ago

This issue still occure when I try to add v-if on my template:

<template #error v-if="errors.length">

With the newest version of Vue. It happens only when building for prod. typescript check doesn't see any issue

hey, did you find a fix? it's happening to me too