Repository: TypeScript
Issue: Wildcard ambient modules declaration override rules 
Labels: Needs Investigation

## Search Terms
wildcard ambient module override

## Suggestion
I could not find written anywhere how wildcard ambient module declaration precedence work in case of overlaps.

In the [original pull request](https://github.com/microsoft/TypeScript/pull/8939/files#diff-08a3cc4f1f9a51dbb468c2810f5229d3R575) "prefix length" was used as the best fit criteria, but I could not locate where that function is located into current code.
Also, prefix length won't help in case of post-fixed `*`, but maybe that was just naming and it actually meant "longer match".

This feature should be better documented into [its handbook page](https://www.typescriptlang.org/docs/handbook/modules.html#wildcard-module-declarations) or, if it has been dropped after first implementation, it would be useful to know why so.

The most [closely related question](https://stackoverflow.com/questions/52373658/angular-typescript-wildcard-module-declaration) I found on StackOverflow doesn't have an answer.

## Use Cases
I have a setup with Vue (Quasar actually) + TypeScript + Jest, using SFC.
I have to mount Vue components into Jest tests (which are written into `.ts` files), but importing SFC won't work (they are not TS files).
Using a shim for all Vue files (the official solution) partially solves this problem, because at least you get typings for the general Vue instance, but you won't get typings for *that* particular SFC (data, props, computed, etc).

I currently separated the TS script from the SFC to be able to get the typings by importing from the two different files. Now I'm trying to define shims for the component `.vue` to work by binding its name with a wildcard to it's TS counterpart.

Unluckily, when I import `./demo/QBtn-demo.vue`, I still get `*.vue` shim instead of the specific component one, and nowhere seems to be found how can I force the override.

If I remove Vue shim, it works, but I'm forced to make a personal shim for *every* component.

I know it's possible by using triple slash references, but that's not the point of this issue.

Current workaround is to import both the `.vue` SFC and the TS script and then explicitly cast the SFC to the type of the specific instance.

## Examples

shims-vue.d.ts
```ts
declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;
}
```

component.d.ts
```ts
declare module '*/QBtn-demo.vue' { // <= works when general Vue shim isn't present
  import QBtnDemo from 'test/jest/__tests__/demo/QBtn-demo'; // <= this is the TS file
  export default QBtnDemo;
}
```

QBtn-demo.vue
```vue
<script lang="ts" src="./QBtn-demo.ts"></script>

<template>
  <div>
    <p class="textContent">{{ input }}</p>
    <span>{{ counter }}</span>
    <q-btn id="mybutton" @click="increment()"></q-btn>
  </div>
</template>
```

QBtn-demo.ts
```ts
import Vue from 'vue';

export default Vue.extend({
  name: 'QBUTTON',
  data: function(): { counter: number; input: string } {
    return {
      counter: 0,
      input: 'rocket muffin',
    };
  },
  methods: {
    increment(): void {
      this.counter++;
    },
  },
});
```

app,spec.ts
```ts
import { createLocalVue, mount } from '@vue/test-utils';
import { Quasar } from 'quasar';
import { VueConstructor } from 'vue';

import QBtnDemo from './demo/QBtn-demo.vue'; // <= Gets types as 'Vue' instead of 'QBtnDemo'

describe('Mount Quasar', () => {
  const localVue = createLocalVue();
  localVue.use(Quasar);

  const wrapper = mount(QBtnDemo, { localVue });
  const vm = wrapper.vm;

  it('has a created hook', () => {
    expect(typeof vm.increment).toBe('function'); // <= TS error: could not find 'increment'
  });

  it('sets the correct default data', () => {
    expect(typeof vm.counter).toBe('number');  // <= TS error: could not find 'counter'
    const defaultData = vm.$data;
    expect(defaultData.counter).toBe(0);
  });

  it('correctly updates data when button is pressed', () => {
    const button = wrapper.find('button');
    button.trigger('click');
    expect(vm.counter).toBe(1);  // <= TS error: could not find 'counter'
  });
});

```

app.spec.ts with casting workaround
```ts
import { createLocalVue, mount } from '@vue/test-utils';
import { Quasar } from 'quasar';
import { VueConstructor } from 'vue';

import QBtnDemoComponent from './demo/QBtn-demo.vue';
import QBtnDemo from './demo/QBtn-demo';

describe('Mount Quasar', () => {
  const localVue = createLocalVue();
  localVue.use(Quasar);

  const wrapper = mount(QBtnDemoComponent as typeof QBtnDemo, { localVue });
  const vm = wrapper.vm;

  it('has a created hook', () => {
    expect(typeof vm.increment).toBe('function'); // <= Infered correctly
  });

  it('sets the correct default data', () => {
    expect(typeof vm.counter).toBe('number'); // <= Infered correctly
    const defaultData = vm.$data;
    expect(defaultData.counter).toBe(0);
  });

  it('correctly updates data when button is pressed', () => {
    const button = wrapper.find('button');
    button.trigger('click');
    expect(vm.counter).toBe(1); // <= Infered correctly
  });
});

```

## Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).