Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: type augmentation and compiler-sfc types w/moduleResolution: bundler (fix #13106) #13107

Merged
merged 3 commits into from Dec 6, 2023

Commits on Oct 24, 2023

  1. fix: allow types wildcard export to match w/o ext

    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:
    ```ts
    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 (when using skipLibChecks: true), and the types aren't available on the vue constructor options or the component instance.
    
    The reason for this can be seen when copying the code into your own project with `"moduleResolution": "bundler"`:
    
    ```
    Invalid module name in augmentation, module 'vue/types/vue' cannot be found.ts(2664)
    module "vue/types/vue"
    ```
    
    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 file with that name, it fails.
    
    What this PR does is provide multiple options to look for when an import matches the "./types/*" export.
    
    1) First we append '.d.ts' and check for that file. I suspect this will be the most common occurence (people that didn't use the extension) so I'm listing it first.
    2) In the event that someone had done `declare module 'vue/types/vue.js'` or `declare module 'vue/types/vue.d.ts'` in their code to work around this issue in prior versions of vue 2.7.x, we still allow for those to match directly.
    
    Fixes: vuejs#13106
    thebanjomatic committed Oct 24, 2023
    Configuration menu
    Copy the full SHA
    7458a5a View commit details
    Browse the repository at this point in the history
  2. fix(types): fixing vue/compiler-sfc types

    Types were broken when consuming the "./compiler-sfc" subpath export from an esm context. To reproduce, you can set `"type": "module"` in package.json, and "moduleResolution": "bundler" or "node16" in your tsconfig.json.
    
    This still works by accident for `"type": "commonjs"` because when it matches `"require": "./compiler-sfc/index.js"` typescript will also check for the corresponding `index.d.ts` file. However, for `"./compiler-sfc/index.mjs"` it winds up checking for `index.d.mts` and doesn't find one.
    
    After this commit, types should be working in all cases for the compiler-sfc entrypoint with moduleResolution: "node", "node16", and "bundler" when the consuming package is listed as "type": "module" or "commonjs".
    thebanjomatic committed Oct 24, 2023
    Configuration menu
    Copy the full SHA
    963c0c2 View commit details
    Browse the repository at this point in the history
  3. chore: moving types condition to top

    This change is somewhat optional as things are working as currently specified, but the typescript team suggests in their documenation that the "types" condition should be listed first to guarantee that its used.
    
    The main difference is that when "types" is listed first, it will match early in the process and just use the types that you specified. If it is listed last, typescript will first match on the "require", "import", "default" conditions that appear higher up in the list. It then does extension modification to try to find corresponding .d.ts files.
    
    In more concrete terms, typescript will wind up looking for "./dist/vue.runtime.esm.d.ts" or "./dist/vue.runtime.common.d.ts" (depending on context) first. Since these files don't exist, it will skip those conditions and keep going until it ultimately finds the "types" entry and use that.
    
    After moving "types" to be the first condition, we get the same result, but skip the extra checks.
    thebanjomatic committed Oct 24, 2023
    Configuration menu
    Copy the full SHA
    cbb59cf View commit details
    Browse the repository at this point in the history