Subscribe on changes!

Returning defineComponent() inference not 'portable' without explicit return type annotation

avatar
May 19th 2022

Link to minimal reproduction

https://stackblitz.com/edit/vue3-issue-repro-5960?file=src%2FApp.vue,src%2Fcomponents%2FGenericList.tsx

Steps to reproduce

  1. Use VS Code with Volar (in Take Over mode)

  2. Create a .tsx file which does export default a generic function which returns a Vue Component using defineComponent()

  3. Use the generic inside props: {} of the defined component

  4. To prevent this error, you need to explicitly specify the return type of the generic function with the DefineComponent and therefore explicitly defining the props type aswell. (e.g. DefineComponent<{myProp: text}>)

What is expected?

Before vue@3.2.34, there was no TypeScript compiler error shown.

What is actually happening?

A TypeScript error is shown:

The inferred type of 'StackedListGeneric' cannot be named without a reference to '.pnpm/@vue+shared@3.2.34/node_modules/@vue/shared'. This is likely not portable. A type annotation is necessary.ts(2742)

System Info

Package Manager: `pnpm` `v7`
Vue: `v3.2.34`

Any additional comments?

The TypeScript compiler error is not shown in Stackblitz. Open it in VS Code to see the compiler warning.


Edit 1: use plain .tsx file instead of violating SFC spec. Edit 2: update link to repro

avatar
May 19th 2022

Why are you doing that in an SFC and not a plain .tsx file?

That's not exactly the usage that's intended and tested against. as it's a violation of the SFC spec.

avatar
May 19th 2022

Why are you doing that in an SFC and not a plain .tsx file?

That's not exactly the usage that's intended and tested against. as it's a violation of the SFC spec.

Thanks for pointing this out!

Just out of habit... Didn't realise it is discouraged 😮.

I moved the function into a plain .tsx file, but the TypeScript error is still shown.

avatar
May 19th 2022

I updated the reproduction to use .tsx and included a demo use case.

The error is in GenericList.tsx:

image

avatar
May 19th 2022

I tested against older versions of vue. The version that introduced this issue seems to be vue@3.2.34.

avatar
May 19th 2022

/cc @pikax Here's one that right up your alley.

avatar
May 19th 2022

Thank you by the way @pikax, for your awesome presentation about Vue types! I'm really interested in Generic Vue components, and your talk helped me to understand the types better. 🙂

avatar
May 19th 2022

Simple workaround (may not work for all scenes): Add @vue/shared as dep & add this to your project.

// type-fix.d.ts
import type {} from '@vue/shared'

After some time of exploration, I found the problem is a bit complex. It's caused by a series of combinations of different packages (vue, vue-tsc) & tools (typescript, pnpm). If the previous solution works, that's great and would be a neat workaround for the moment.

However if your project is large, that solution may still have some problems. My recommendation is locking all version of vue & related packages to 3.2.33 (including nested deps).

Seems @vue/test-utils and class & style prop for component in tsx is broken with vue@3.2.34. See

image
avatar
May 20th 2022

I believe this was caused by https://github.com/vuejs/core/commit/98b821d94a0a0fb4d7701809da6bec331a47e6e5 which altered the argument order of DefineComponent.

Should be fixed by 8071ef47 which reverts the change. (Update: out in 3.2.35)

avatar
May 24th 2022

I could not reproduce this issue with vue@3.2.34 anymore, seems Volar uses the newer version of vue@3.2.36 with the fixed regression.