Repository navigation
Let a config type the modify config options - #409
Conversation
d62dfa9 to
fe7730b
Compare
fe7730b to
32c9d63
Compare
|
Honestly, this change doesn't look good. It is very rare feature and we have too many changes which could create issues in the future. Let's keep simple here and ask user to type config. Is it OK? |
|
Before deciding, here is what the current declaration actually allows, plus the two alternatives that came up. Measured with
Nothing compiles against what we have today, not even Dropping the So there are two shapes to choose from:
If the objection is the machinery rather than the option, I will reduce the PR to the first one. If the option is rare enough that its type may stay as it is, that is a decision too — but it is why the current state is worth one of the two, rather than neither. |
|
Let's go with modifyEsbuildConfig((config: EsbuildConfig) => {
}) |
32c9d63 to
c6799b3
Compare
|
Done — reduced to the three declarations: modifyEsbuildConfig?: (config: object) => object
modifyRolldownConfig?: (config: object) => object
modifyWebpackConfig?: (config: object) => objectNo peers, no One detail beyond the generic: the parameter is required rather than The README line that called the esbuild option's config "webpack" is fixed in the same commit. |
c6799b3 to
ccb1cef
Compare
`modifyEsbuildConfig`, `modifyRolldownConfig` and `modifyWebpackConfig`
were typed as generic functions, `<T extends object>(config?: T) => T`,
and nothing compiles against that. The optional parameter types the
argument as `T | undefined`, which can never be returned as `T`, and a
modifier annotated with the bundler's own type fails just as well,
because a returned object can never be the type parameter:
modifyEsbuildConfig: config => config
// Type 'T | undefined' is not assignable to type 'T'
modifyEsbuildConfig: (config: BuildOptions) => ({ ...config, external: [] })
// Type '{ …; external: string[]; }' is not assignable to type 'T'
They take and return `object` now, so a config annotates the parameter
with the bundler's own type: the option wants a function over a config
the core does not know, and the config is what has that type.
modifyEsbuildConfig: (config: BuildOptions) => ({ ...config, external: [] })
The parameter is required, because the plugins always call a modifier
with the config they have just built (`check.esbuildConfig =
check.modifyEsbuildConfig(check.esbuildConfig)` in step 20); optional
would leave an unannotated modifier with `object | undefined`, unable to
write to the config at all.
The README entry for `modifyEsbuildConfig` mentioned the webpack config.
ccb1cef to
7e1c9d3
Compare
|
Thanks. Types was released in 14.2.0. |
modifyEsbuildConfig,modifyRolldownConfigandmodifyWebpackConfigwere typed as generic functions, and nothing compiles against that:<T>(config?: T) => Tconfig => configType 'T | undefined' is not assignable to type 'T'config => ({ ...config, external: ['dep'] })Type '{ external: string[]; }' is not assignable to type 'T'config => { config.external = ['dep']; return config }Property 'external' does not exist on type 'T'(config: BuildOptions) => ({ ...config, external: ['dep'] })Types of parameters 'config' and 'config' are incompatibleThe optional parameter types the argument as
T | undefined, which can never be returned asT, and the generic return is what rejects a modifier annotated with the bundler's own type.Why the generic cannot be kept
<T extends object>(config: T) => Tpromises "for everyT, return that sameT", which a modifier typed for one config cannot promise — withT = { a: 1, b: 2 }nothing guarantees the returned object still hasb. TypeScript requires the source to be generic as well, and<T extends object>(config: T) => configis accepted, but no config writes that. Upstream: #17574 (open suggestion) and #5494, closed as By Design with this same error.What this does instead
The core does not know the bundlers' types, so the config brings them:
An untyped arrow still compiles; it just checks nothing, and reading or writing the config is what needs the annotation.
The parameter is required, because the plugins always call a modifier with the config they have just built —
check.esbuildConfig = check.modifyEsbuildConfig(check.esbuildConfig)in step 20, and the same in the webpack and rolldown plugins. Withconfig?the argument isobject | undefined, so a modifier cannot write to the config without handlingundefined.No new dependencies, no peer declarations, no lockfile change. The README line that described the esbuild option as modifying the webpack config is fixed as well.
Verification
tsc --strictagainst the real esbuild, rolldown and webpack types: the annotated modifiers above compile, including writing to a webpack config (config.mode = 'production'), under bothnodenextandbundlerresolution.oxlintis clean.