vuejs / vue

This is the repo for Vue 2. For Vue 3, go to https://github.com/vuejs/core

Home Page:http://v2.vuejs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Type augmentation is broken when using typescript's moduleResolution: "Bundler" option

thebanjomatic opened this issue · comments

Version

2.7.15

Reproduction link

codesandbox.io

Steps to reproduce

yarn install
yarn test

What is expected?

The project should typecheck without errors

What is actually happening?

The type augmentation fails and as a result, there are type errors that need to be worked around.


When using typescript's "moduleResolution": "bundler" option, we currently get a bunch of type errors, particularly when trying to extend the types, or when consuming other packages which extend the types (vue-router, pinia, etc).

For example, vue-router extends the types as follows:

declare module 'vue/types/vue' {
  interface Vue {
    $router: VueRouter
    $route: Route
  }
}

declare module 'vue/types/options' {
  interface ComponentOptions<V extends Vue> {
    router?: VueRouter
    beforeRouteEnter?: NavigationGuard<V>
    beforeRouteLeave?: NavigationGuard<V>
    beforeRouteUpdate?: NavigationGuard<V>
  }
}

But this silently fails, and the types aren't available on the vue constructor options or the component instance.

image
Object literal may only specify known properties, and 'router' does not exist in type 'ComponentOptions<Vue<Record<string, any>, Record<string, any>, never, never, (event: string, ...args: any[]) => Vue<Record<string, any>, Record<string, any>, never, never, ...>>, ... 7 more ..., ComponentOptionsMixin>

The reason for this can be seen when copying the code into your own project with "moduleResolution": "bundler":

image
Invalid module name in augmentation, module 'vue/types/options' cannot be found.ts(2664)
module "vue/types/options"

What is happening is that once "moduleResolution" is set to "bundler", the "exports" maps in package.json starts being used, and there are some peculiarities with wildcard matching that we don't appear to be accounting for here. In particular, wildcard matching is going to require that the full path to the file is provided. So, when we specify declare module 'vue/types/vue' it is going to look for a file on disk with the relative path: ./types/vue, and since there is no extensionless file with that name, it fails.

You could technically work around this by explicitly specifying declare module 'vue/types/vue.js' or declare module 'vue/types/vue.d.ts' when you are doing the type augmentation, but I think it would be better to just fix the "exports" definition to allow you to specify the file name without the extension as otherwise we'd need to release updates to many other packages and user code vs just one.