microsoft / microsoft/TypeScript
Feature Request: Make "loaders" a first class citizen of the language
@rbuckton is already working on this.
Since Aug 23, 2019.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
This follows some thoughts I had with "The Maybe Future of Frontend Tooling" and picks up some use cases which aren't covered by the current (awesome!) language server plugin support 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.
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" and "What's in a language?". 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?*).
- Either write an interface for them directly (e.g.
-
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 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. 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?*';). 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 nofetchused 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.