core icon indicating copy to clipboard operation
core copied to clipboard

Can't use generic prop type when definition includes intersection with generic params?

Open superfreddialpad opened this issue 2 years ago • 18 comments

Vue version

3.3.4

Link to minimal reproduction

https://play.vuejs.org/#eNqFUbFOwzAQ/ZWTBwJSaRamNI3EgsSGRMXkJW6urYXjs2ynVRTl3zmHQCMGOtnne/feu+dBPDu3PncoClGGvdcuQsDYOTC1PW6liEGKSloA3TryEV6IXiO2cPDUQrbO5zpRZAm2JxsiHIhgC0M6C3hagap9AdkJjaFsBTp86KCVwQKi7xDGjbTSlvm3PqtxwZzO1BEn7fJH9fyotG3YFhNLATl3y3wB5TLE3qSroqaHIU2rev959NTZpgBluGC5ZNQQm7qcdMTpYZwszNNiJRab3Qgn9g5TMNeVbdcq9JvEOTXfqcU3Ty6Uu4pRO7hj5CIGRWSwtgkvbYMHbWf4dZD5q+r+4f+cGn3mjMKJLuzul59Nzh8y2YNxLHNG/g1PjF+nxbYT

Steps to reproduce

type Foo = { foo: number; }
type SomeProps<T> = T & { isVisible: boolean }

What is expected?

this should be valid typescript:

https://www.typescriptlang.org/play?#code/C4TwDgpgBAYg9nKBeKBvKAzBAuKA7AVwFsAjCAJygF8AoUSKAZTiIgAVy4wBnAHgBUAfMij8oAMjRQAltwBqs6SQA2EXCQSqAhnmo0AxnDzdgmHExbtOPXvDjCU6LHFwBmADQz5ilWqjByAmgqAG4aaQwoAApnADpZBW4lVQBKKENjOFVY5TgAcxiEFJCgA

What is actually happening?

compile error:

1:55:02 AM [vite] Internal server error: [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

/testdir/src/FooItem.vue
1  |  <script setup lang="ts">
2  |  type Foo = { foo: number }
3  |  type SomeProps<T> = T & { isVisible: boolean }
   |                      ^
4  |
5  |  defineProps<SomeProps<Foo>>()
  Plugin: vite:vue
  File: /testdir/src/FooItem.vue
      at ScriptCompileContext.error (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:15841:11)
      at innerResolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17966:20)
      at resolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17902:35)
      at /testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17924:31
      at Array.map (<anonymous>)
      at innerResolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17924:20)
      at resolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17902:35)
      at innerResolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17947:16)
      at resolveTypeElements (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:17902:35)
      at resolveRuntimePropsFromType (/testdir/node_modules/.pnpm/@[email protected]/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:19312:20)

System Info

  System:
    OS: macOS 12.0.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 44.49 GB / 64.00 GB
    Shell: 5.1.4 - /usr/local/bin/bash
  Binaries:
    Node: 16.20.0 - ~/.nvm/versions/node/v16.20.0/bin/node
    npm: 8.19.4 - ~/.nvm/versions/node/v16.20.0/bin/npm
  Browsers:
    Chrome: 113.0.5672.126
    Chrome Canary: 116.0.5806.0
    Firefox: 111.0
    Safari: 15.1
    Safari Technology Preview: 15.4
  npmPackages:
    vue: ^3.3.2 => 3.3.4

Any additional comments?

I'm not actually sure if I'm characterizing this correctly, but it seems like the sfc compiler cannot handle props whose type intersects one of its own generic parameters.

full pnpm lockfile if that's useful: https://gist.github.com/superfreddialpad/248efe40250d772938f31a2440e54e35

superfreddialpad avatar Jun 02 '23 06:06 superfreddialpad

Pretty sure this is a duplicate of #8468

justin-schroeder avatar Jun 06 '23 18:06 justin-schroeder

@justin-schroeder They're not exactly the same.

edison1105 avatar Jun 07 '23 00:06 edison1105

I get the same error when I use an imported type as an alias. I'm not 100% sure if these errors are related.

<script setup lang="ts">
import type * as T from './Foo.types'
defineProps<T.Props>()
</script>

Here is the link for reproduction: https://play.vuejs.org/#eNqFU8lu2zAQ/ZUBL24LVz6kJ0UJ0BYpkB7aoDV64kXLWGZCkQSH8gJD/94hJTtCUTgncRZy3jI6ic/OZbseRS4Kqr1yAQhD70CXpr2TIpAU99IAqM5ZH+CbtY8BO9h428EiW01xfGIR22prKMDGWriDU/zm8GkJVelzWGxRa7tYgqI/ilSlMYfge4ThVhppitU4n6dxwG86XQZMs4vz1N3HSpmGYfHDUsCKq8Vq1sohhaOOx8o2RzjF21VZv7Te9qbJodIc8LgIVFsGtd+qgCkxJAjTbbEUM2ZviDNJE44O4QOUBOu5PFnME4sjTYMbZfDJW0fFOkvf+3fvr1Nv1I5p09bueeBFOZ47aZxEhmEoVtz5rx5MIxBbslFt9kzWMJEkiRS17ZzS6H+6oNgyKfJRrFgr2ab995SL/izP+XqL9ct/8s90iDkpnjwS+h2ju9RC6VsMY/nh9w888PlS7GzTRy5Xir+QrO4jxrHtC9vIsGd9Ce1jskCZdk0Ph4CGzqQi0ORu6peC3fx6hfor3JvsZtqKYVyG0ccsEIuIh1fHk41p22d7XVmrsTS34x9AwTM03nMx/AVHMyjZ

sevilyilmaz avatar Oct 23 '23 08:10 sevilyilmaz

Hello !! I have done pnpm update after your update but, i always have the same error.

this is my code

`export default interface IDynamicSelectInput<E, K, L>{

//props: PropsType<K> & L; props: PropsType<K> & L emits: EmitsType<E>; }`

this is error

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

/home/trandx/dev/Nucle-x/sso/_mono/packages/ui/src/components/atoms/list/index.ts 11 | //(event: "change", elt: OptionsType | OptionsType[] ): void; 12 | //(event: 'remove'): void 13 | } & T; | ^ 14 |
15 | type optionFormatType = { name: string; value: valType };`

Trandx avatar Dec 04 '23 08:12 Trandx

Yep I also tested the latest version (3.3.10) and still have the same issue.

amritk avatar Dec 04 '23 18:12 amritk

@Trandx your code doesn't show how the interface is used in the component.

@amritk If you are still having the same error, make sure to provide the exact and complete code that is causing the error because there can be many different ways of using generics.

yyx990803 avatar Dec 04 '23 18:12 yyx990803

I am not sure if it is connected, but I have simillar problem even after updating from 3.3.4 to 3.3.13

// Those types are in a separate file and are imported into the component

export type ExtractExtraApiGetRequestParams<T extends ApiGetRequestParams> = Subtract<
  T,
  ApiGetRequestParams
>;

export type Subtract<T extends U, U> = Pick<T, Exclude<keyof T, keyof U>>;

const props = defineProps<ExtractExtraApiGetRequestParams<ApiAuditGetRequest>>();

ApiAuditGetRequest extends ApiGetRequestParams.

And I am getting: [plugin:vite:vue] [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

adampolyanskiy avatar Dec 20 '23 07:12 adampolyanskiy

We ran into this when trying to use zod type inference.

adambiggs avatar Apr 24 '24 18:04 adambiggs

I still have problems with generic on the latest version. Even the simple following code fails to compile:

export type Test<T> = T

ClementNerma avatar Jun 08 '24 21:06 ClementNerma

Okay, thank you for your solution. But, I think that my issue has already resolved in the resent version that contents Typescript 5.4

Le sam. 8 juin 2024 à 22:55, Clément Nerma @.***> a écrit :

I still have problems with generic on the latest version. Even the simple following code fails to compile:

export type Test<T> = T

— Reply to this email directly, view it on GitHub https://github.com/vuejs/core/issues/8482#issuecomment-2156200684, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKENQXTGQCRWEHWYSAG4TY3ZGN4UJAVCNFSM6AAAAAAYX3IKCOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCNJWGIYDANRYGQ . You are receiving this because you were mentioned.Message ID: @.***>

Trandx avatar Jun 09 '24 02:06 Trandx

I tried to re-use vuetify component's props type FormInputProps = VTextField['$props'] and as under the hood Vuetify exports via InstanceType<typeof VTextField>, also ended up with error [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

version 3.4.29

vkrepkiy avatar Jun 17 '24 09:06 vkrepkiy

I'm also getting the same error when trying to import an inferred zod type [plugin:vite:vue] [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

import { z } from 'zod';

export const EmailVerificationViewPropsSchema = z.object({
  initialStage: z.enum(['send', 'resend', 'verify', 'changeEmail']),
  email: z.string().email(),
});

export type EmailVerificationViewProps = z.infer<typeof EmailVerificationViewPropsSchema>;

I'm importing it inside script setup:

<script setup lang="ts">
import type { EmailVerificationViewProps } from './view-props';

const props = defineProps<EmailVerificationViewProps>();

/* ... */
</script>

rcomesan avatar Jun 20 '24 14:06 rcomesan

🙏 thanks

Le jeu. 20 juin 2024 à 15:14, rcomesan @.***> a écrit :

I'm also getting the same error when trying to import an inferred zod type [plugin:vite:vue] @.***/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

import { z } from 'zod'; export const EmailVerificationViewPropsSchema = z.object({ initialStage: z.enum(['send', 'resend', 'verify', 'changeEmail']), email: z.string().email(),}); export type EmailVerificationViewProps = z.infer<typeof EmailVerificationViewPropsSchema>;

I'm importing it inside script setup:

— Reply to this email directly, view it on GitHub https://github.com/vuejs/core/issues/8482#issuecomment-2180817508, or unsubscribe https://github.com/notifications/unsubscribe-auth/AKENQXRWG5NGMLLBFHNMY5TZILPUHAVCNFSM6AAAAAAYX3IKCOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOBQHAYTONJQHA . You are receiving this because you were mentioned.Message ID: @.***>

Trandx avatar Jun 20 '24 15:06 Trandx

Any updates here? I am having this problem when importing InferType from yup

Sinled avatar Jul 24 '24 16:07 Sinled

I get a similar error when using prop extraction from the element-plus library.

<template>
  <ElButton v-bind="$props" :icon>
    <slot />
  </ElButton>
</template>

<script setup lang="ts">
import { ElButton } from 'element-plus'
import type { IconDefinition } from '@fortawesome/fontawesome-svg-core'

type TElButtonProps = InstanceType<typeof ElButton>['$props'];

const props = defineProps<TElButtonProps & {
  awesomeIcon?: IconDefinition
}>()

const GenericIconComponent = resolveComponent('Icon')

const icon = h(GenericIconComponent, { name: props.awesomeIcon })
</script>

pavlo-hadzheha avatar Aug 01 '24 14:08 pavlo-hadzheha

We massively rely on inferred types from zod schemas and run into this issue. Is this a design limitation of @vue/compiler-sfc or something that can be fixed?

juni0r avatar Sep 26 '24 10:09 juni0r

Hi! I'm also getting error while use zod inference in vue setup [plugin:vite:vue] [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

types.ts

export const PageSchemaZ = z.object({
  title: z.string(),
  subtitle: z.string(),
});

export type PageSchema = z.infer<typeof PageSchemaZ>;

SomePage.vue

<script setup lang="ts">
import type { PageSchema } from "./types";
...
const props = defineProps<PageSchema>();
...
</script>

Is there any workaround? It seem like current workaround is just manually create types based on zod schema, but that's not the best approach

arthurseredaa avatar Jun 05 '25 09:06 arthurseredaa

Problem still persists with inferred types from zod schema.

imyourm8 avatar Jun 15 '25 14:06 imyourm8

is there a plan to work on this ? zod is getting really popular

Mdev303 avatar Aug 11 '25 00:08 Mdev303

@arthurseredaa, @imyourm8, @Mdev303

There is a workaround for zod users.

import { z } from 'zod/v4-mini';

type OptionalKeys<T> = {
  [K in keyof T]-?: object extends Pick<T, K> ? K : never;
}[keyof T];

type RequiredKeys<T> = Exclude<keyof T, OptionalKeys<T>>;

type MandateOptionalWithUndefined<T> = {
  [K in RequiredKeys<T>]: T[K];
} & {
  [K in OptionalKeys<T>]-?: NonNullable<T[K]> | undefined;
};

export const zodToVueProps = <
  Z extends z.ZodMiniObject,
  T extends MandateOptionalWithUndefined<z.output<Z>>,
>(
  zod: Z,
) =>
  // Here only an array of keys is created for registration in the component, but the type description is simulated for correct type extraction.
  Object.keys(zod.def.shape) as {
    [K in keyof T]: {
      required: Extract<T[K], undefined> extends never ? true : false;
      type: () => T[K];
    };
  };

const zodProps = z.object({
  string: z.string(),
  number: z.number(),
  boolean: z.boolean(),
  stringArray: z.array(z.string()),
  yesOrNo: z.union([z.literal('yes'), z.literal('no')]),
  optionalNumber: z.optional(z.number()),
  booleanOrUndefined: z.union([z.boolean(), z.undefined()]),
});

const props = defineProps(zodToVueProps(zodProps));

/*
const props: {
    readonly string: string;
    readonly number: number;
    readonly boolean: boolean;
    readonly stringArray: string[];
    readonly yesOrNo: "yes" | "no";
    readonly optionalNumber?: number | undefined;
    readonly booleanOrUndefined?: boolean | undefined;
}
*/


Vyachean avatar Oct 15 '25 08:10 Vyachean