Repository: TypeScript
Issue: Feature Request: Make "loaders" a first class citizen of the language
Labels: Needs Investigation

This follows some thoughts I had with _["The Maybe Future of Frontend Tooling"](https://medium.com/@pipopeperoni/the-maybe-future-of-frontend-tooling-80e6d96f8125)_ and picks up some use cases which aren't covered by the current (_awesome_!) [language server plugin support](https://github.com/RyanCavanaugh/sample-ts-plugin) as far as I know. I also created https://github.com/Microsoft/TypeScript/issues/15589 which refers to _linter rules_. This issue is about _loaders_ - in the sense how they were [introduced by webpack](https://webpack.js.org/concepts/loaders/).

In general both issues - this one and https://github.com/Microsoft/TypeScript/issues/15589 - remind me of Cheng Lous talks about [_"Taming the Meta Language"_](https://www.youtube.com/watch?v=_0T5OSSzxms) and [_"What's in a language?"_](https://www.youtube.com/watch?v=24S5u_4gx7w). Linters and loader are not a part of the current language in a strict sense, but part of our meta language and it is good to formalize more of them so they become a language construct. (Part of Cheng Lous talks is about why reason for example doesn't have a separate linter.)

**Current state**

- Loaders like they are used by webpack allows us to require non JavaScript files (or non TypeScript files) and transform them into a JavaScript/TypeScript "file" _or_ require JavaScript/TypeScript files and transform them so they'll have a different interface.

- TypeScript supports loaders in two ways:
  - Either write an interface for them directly (e.g. `declare module 'foo-loader?param=bar!../test';`).
  - Or use a wild card (e.g. `declare module 'foo-loader?*`).

- This is either cumbersome/error prone and/or limited, because they interfaces can't be typed in a very dynamic way.

- Two use cases which we currently have, which I'd like to point out:

**Use case 1**

We have translations in a file called `en.properties` (and other files for other languages) which could look like this: 

```
say-something={gender, select, f {She} m {He}} is great.
```

I'd like to import this file as `import { saySomething } from '../i18n/en.properties';` which would have an interface like this:

```
declare module '../i18n/en.properties' {
  /**
   * `en`: {gender, select, f {She} m {He}} is great.
   * `de`: {gender, select, f {Sie} m {Er}} ist toll.
   */
  export function saySomething(data: { gender: 'f' | 'm' }): string;
}
```

[We currently need to pre-compile our translations](https://github.com/Mercateo/ws/blob/master/src/lib/i18n/compile.ts#L154) and emit a `.d.ts` and a `.js`, so we import the `.js` instead of the `.proprties`. Only then we get this complex interface.

**Use case 2**

We add new exported functions to existing modules [so we can mock them easily](https://github.com/Mercateo/import-inject-loader). _What_ will be added depends on the query parameters of the loader. It could look like this: `'import-inject-loader?fetch!../src/get-users'`.

E.g. using `import-inject-loader?fetch` will add two new exported functions to `../src/get-users`: `ilOverwriteFetch` and `ilResetAll`.

Currently we need declare every module which uses `import-inject-loader` as `any` ([`declare module 'import-inject-loader?*';`](https://github.com/Mercateo/frontend-unit-tests-examples/blob/master/typings/custom.d.ts#L7)). Everything else would be too hard to maintain.

**What I'd like to see**

* I would like to get proper typings for imported files where the content changes the interface (= use case 1) without precompiling, but with importing the file directly.

* I would like to get proper typings for files with existing interfaces, but which are transformed (in the easiest case just extended) into a different interface without loosing the original interface (= use case 2).

* I would like to get proper typings for imported modules, when the interface changes, because of loader options (= use case 2).

* I would like to get assistance when configuring loaders through query parameters (= use case 2, e.g. show an error, when I write `'import-inject-loader?fetch!../src/get-users'`, if there is no `fetch` used inside `../src/get-users`).

---

If something like that isn't in the scope of a TypeScript core team, I could think of giving a new "TypeScript tooling team" this scope which develops closely together with the TypeScript core team in a similar fashion like the VS code team.

I think it is important to address these meta language issues _somehow_ in an official way to get a nice TypeScript ecosystem.