webpack: [5.0.0] built-in .d.ts is missing some(or many) types from @types/webpack

Bug report

Encountered this while trying to upgrade my loader to webpack@5. In webpack@4, with @types/webpack, I could create a fully typed loader. In webpack@5, there’s aren’t any exported types for the Loader or the LoaderContext

What is the expected behavior?

Auto generate (?) or just include these interfaces: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/6a1c6a5567fa177396fa802b2367ec34e1028eea/types/webpack/index.d.ts#L2116

Other relevant information: webpack version: 5.0.0 Node.js version: 14.13.1 Operating System: Fedora 32 Additional tools:

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 19
  • Comments: 70 (29 by maintainers)

Most upvoted comments

to add, also missing ConfigurationFactory which was available in @types/webpack

LoaderContext type is not defined nor exported in lastest webpack@5, as far as I can tell… I had to inline the type (partial; just what I needed) in loaders I’ve created.

https://github.com/webpack/webpack/blob/v5.28.0/lib/NormalModule.js#L469

EDIT: https://github.com/AviVahl/ts-tools/blob/main/packages/webpack-loader/src/loader-types.ts

@AviVahl Let’s keep open until we solve ConfigurationFactory/MultiConfigurationFactory and then close in favor single issues

You don’t need ReturnType here

I see, make sense… we need think how better to do it, maybe in future we will have more args…

And if this was a typescript project, I probably would.

Instead, I would have to learn yet another syntax for defining and re-exporting interfaces/symbols via jsdocs, plus the custom types building infrastructure in this project. Not fun, and drives many typescript contributors, like myself, away.

If I’m opting to open an issue instead of creating a PR, you may want to ask yourself how easy it is to contribute.

The options parameter of stats.toJson and stats.toString was properly typed in @types/webpack. now it’s any.

It seems clunky to put the responsibility on consumers to define the types they’re concerned with, especially since the process for it is mostly just boilerplate (looking up the type from the configuration object). If webpack (CLI?) knows what properties it expects in as CLI arguments shouldn’t those be exposed to consumers? Even if it’s just something as simple as:

type Args = { [k in keyof Configuration]: string }

I’d rather make type safety the default case rather than having it rely on consumers correctly defining the configuration function type.

And I don’t understand why mode can’t be string | undefined when the doc itself says so. I do think mode should be typed specifically as it is documented to use a configuration function in order to obtain argv.mode (see bottom of the page linked).

It is generally bad TS practice to use any or as when alternatives are possible as they bypass the type checker (and even more less desirable to recommend it to lib consumers). If you don’t want or cannot maintain a list of supported properties, that’s totally ok, but in that case ConfigurationFactory should be a generic so that consumers can set the corresponding types like you suggested 😃

I think something like the following would make people needing this happy (but would love feedback from others, /Cc @vitoyucepi, @kavsingh, @MarkKoester):

import type { Configuration } from 'webpack';

export type ConfigurationFactory<T, U> = (env: T, args: U) => Configuration;

(I personally would prefer ConfigurationFactory<T, U = { mode?: Configuration['mode'] }> or something like that but if you don’t want to maintain that then <T, U> is a good start)

The example from the Webpack doc would become something along the lines of:

import type { ConfigurationFactory } from 'webpack';

const configFactory: ConfigurationFactory<never, { mode?: Configuration['mode'] }> = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};

export default configFactory;

To be honestly, webpack don’t know this stuff, because only object allowed, function/promises allowed by webpack-cli so you can use:

import type { Configuration } from 'webpack';

export default (env: Record<string, any>, args: Record<string, any>): Configuration => {
  return { mode: 'production' }
}

Don’t know why these types was added to webpack types + they are wrong.

Also, is this.remainingRequest (LoaderContext) the same as getRemainingRequest from loader-utils? I saw it in the type, but nowhere in the docs: https://webpack.js.org/api/loaders/ If it is, is it safe to use in webpack@4 as well? 😐

Please use this.remainingRequest, getRemainingRequest was deprecated for webpack v4 and v5 https://github.com/webpack/loader-utils/blob/master/lib/getRemainingRequest.js#L5, loader-utils will be deprecated in near future

Still missing ConfigurationFactory and MultiConfigurationFactory.

I’ve created a package with these types as a part of my project. But I still think this types should be a part of the upstream package.

Please clarify, what is ConfigurationFactory and MultiConfigurationFactory, we never have these types

Still missing ConfigurationFactory and MultiConfigurationFactory.

I’ve created a package with these types as a part of my project. But I still think this types should be a part of the upstream package.

@sokra The errors in callback signatures of functions of InputFileSystem and OutputFileSystem need to be nullable to align with the node and memfs types (ref: types/node/fs.d.ts). I’ve created a PR to address this. This is my first PR to webpack, so let me know if I’m missing something, thanks 😃

Are the ConfigurationFactory and MultiConfigurationFactory types in webpack’s scope or is that something that would ideally be exported from webpack-cli? The comments in this PR #11964 make it seem like it would be webpack-cli’s responsibility.

Types for reference (from @types/webpack):

 type ConfigurationFactory = ((
      env: string | Record<string, boolean | number | string> | undefined,
      args: CliConfigOptions,
  ) => Configuration | Promise<Configuration>);

  type MultiConfigurationFactory = ((
      env: string | Record<string, boolean | number | string> | undefined,
      args: CliConfigOptions,
  ) => Configuration[] | Promise<Configuration[]>);

Awesome, thanks. I’m mainly reporting it to resolve stuff for other people. I’ve got workarounds in place for all reported issues.

@evilebottnawi thanks for the tip.

We can push that even further, extracting the return values of functions by using ReturnType. This is an excerpt from a file that I’m using in my project to get back some of the missing types.

export type Watching = ReturnType<Compiler["watch"]>;
export type WebpackLogger = ReturnType<Compilation["getLogger"]>;

I still think that a coherent typings file should export the entire surface of names that are used to define the “top-level” types. However, these techniques mitigate the issue somewhat.

I think you can send a PR for exporting more types as per your need. Types can be exposed by adding @typedefs to lib/index.js. Run yarn special-lint-fix to update the typings.