Skip to content

Invalid component types generated for generic Vue components when migrating from Typescript 5.4.4 -> 5.5.2 #4577

@its-lee

Description

@its-lee

Vue - Official extension or vue-tsc version

[email protected], [email protected]

VSCode version

1.90.1 (Universal)

Vue version

3.4.21

TypeScript version

5.5.2

System Info

System:
    OS: macOS 14.2.1
    CPU: (8) arm64 Apple M1 Pro
    Memory: 79.45 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.14.0 - ~/.nvm/versions/node/v20.14.0/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 10.7.0 - ~/.nvm/versions/node/v20.14.0/bin/npm
    pnpm: 8.9.2 - ~/Library/pnpm/pnpm
  Browsers:
    Chrome: 126.0.6478.127
    Safari: 17.2.1

Steps to reproduce

See reproduction https://github.com/its-lee/vue-tsc-incompatible-vue-lib-types, but:

  1. Use the typescript version noted above, the following was working fine on Typescript 5.4.4 but not after migrating to 5.5.2
  2. Create a package (A) containing a Generic Vue component, build it and generate types for the Component.
  3. Create another package (B) consuming that package and try to use that component
  4. Run vue-tsc on package B

What is expected?

vue-tsc should find no Typescript errors and the generated types for package A should be consistent.

What is actually happening?

  1. vue-tsc fails when typechecking package B due to failing to interact with generic types. E.g. in the reproduction, this was from a scoped slot arg with a typed property using the generic type:
➜  package-b git:(main) npx vue-tsc
src/ComponentB.vue:19:39 - error TS2339: Property 'text' does not exist on type 'BaseRow'.

19     <template v-slot="{ row }">{{ row.text }}</template>
                                         ~~~~


Found 1 error in src/ComponentB.vue:19
  1. The generated types for the component contain missing declarations, e.g. from the reproduction:
export type BaseRow = {
  value: string;
};
declare const _default: <Row extends BaseRow>(
  __VLS_props: Awaited<typeof __VLS_setup>["props"],
  __VLS_ctx?: __VLS_Prettify<
    Pick<Awaited<typeof __VLS_setup>, "attrs" | "emit" | "slots">
  >,
  __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"],
  __VLS_setup?: Promise<{
    props: __VLS_Prettify<
      Pick<
        Partial<{}> &
          Omit<
            {} & import("vue").VNodeProps &
              import("vue").AllowedComponentProps &
              import("vue").ComponentCustomProps &
              Readonly<import("vue").ExtractPropTypes<{}>>,
            never
          >,
        never
      > & {
        nonGeneric: string;
        rows: Row[];
      }
    > &
      __VLS_BuiltInPublicProps;
    expose(exposed: import("vue").ShallowUnwrapRef<{}>): void;
    attrs: any;
    slots: ReturnType<
      () => {
        default?(_: { row: Row }): any;
      }
    >;
    emit: {};
  }>
) => import("vue").VNode<
  import("vue").RendererNode,
  import("vue").RendererElement,
  {
    [key: string]: any;
  }
> & {
  __ctx?: Awaited<typeof __VLS_setup>;
};
export default _default;

type __VLS_Prettify<T> = {
  [K in keyof T]: T[K];
} & {};
//# sourceMappingURL=ComponentA.vue.d.ts.map

A couple of issues with this generated .d.ts that if I change resolves the issue:

  • __VLS_BuiltInPublicProps isn't defined anywhere - hackily commenting this out helps resolve the issue but it should be defined somewhere in the same way __VLS_Prettify has been?
  • __VLS_expose?: NonNullable<Awaited<typeof __VLS_setup>>["expose"] uses NonNullable - which is good, as __VLS_setup could be undefined. However, __VLS_props and __VLS_ctx incorrectly don't use NonNullable on Awaited<typeof __VLS_setup>, so they are generating TS errors as e.g. Awaited<typeof __VLS_setup>['props'] won't work when Awaited<typeof __VLS_setup> is undefined.

Link to minimal reproduction

https://github.com/its-lee/vue-tsc-incompatible-vue-lib-types

Any additional comments?

Ran into this when migrating a Vue component library from Typescript 5.4.4 -> 5.5.2.

For reference, typescript 5.4.4 generated this which is consistent and worked A-OK, containing no type errors and not using any types that aren't declared anywhere (e.g. __VLSBuildInPublicProps) - it's quite substantially different which is surprising!

export type BaseRow = {
    value: string;
};
declare const _default: <Row extends BaseRow>(__VLS_props: {
    nonGeneric: string;
    rows: Row[];
} & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, __VLS_ctx?: {
    attrs: any;
    emit: {};
    slots: {
        default?(_: {
            row: Row;
        }): any;
    };
} | undefined, __VLS_expose?: ((exposed: import('vue').ShallowUnwrapRef<{}>) => void) | undefined, __VLS_setup?: Promise<{
    props: {
        nonGeneric: string;
        rows: Row[];
    } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps;
    expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
    attrs: any;
    slots: {
        default?(_: {
            row: Row;
        }): any;
    };
    emit: {};
}>) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
    [key: string]: any;
}> & {
    __ctx?: {
        props: {
            nonGeneric: string;
            rows: Row[];
        } & import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps;
        expose(exposed: import('vue').ShallowUnwrapRef<{}>): void;
        attrs: any;
        slots: {
            default?(_: {
                row: Row;
            }): any;
        };
        emit: {};
    } | undefined;
};
export default _default;

type __VLS_Prettify<T> = {
    [K in keyof T]: T[K];
} & {};
//# sourceMappingURL=ComponentA.vue.d.ts.map

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood reproduction ✨This issue provides a good reproduction, we will be able to investigate it first

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions