Skip to content

fix(decorators): read the constructor implementation, not its first overload - #635

Open
edbzn wants to merge 1 commit into
voidzero-dev:mainfrom
edbzn:fix/ctor-overloads
Open

edbzn wants to merge 1 commit into
voidzero-dev:mainfrom
edbzn:fix/ctor-overloads

Conversation

@edbzn

@edbzn edbzn commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

Fixes #630.

Problem

With constructor overloads, every constructor lookup took the first constructor member, which is an overload signature. The factory then injected only that signature's parameters, so the implementation's extra dependencies were undefined at runtime. setClassMetadata's ctor params were wrong in the same way. The implementation's @Optional() was never compiled, so it stayed in the output and a downstream TS transform lowered it to __param. This applies to @Injectable, @Component, @Directive, @Pipe and @NgModule, and to JIT ctorParameters.

Fix

A new helper, util::find_constructor, returns the constructor that has a body. This mirrors ngtsc's TypeScriptReflectionHost.getConstructorParameters (packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts) for non-declaration files, and the JIT downlevel_decorators_transform.ts, which skips constructors without a body. These lookups now use it:

  • factory deps for Injectable, Component, Directive, Pipe and NgModule (extract_constructor_deps)
  • setClassMetadata ctor params (build_ctor_params_metadata) and the import-elision pass that mirrors their types
  • param-decorator stripping (for_each_constructor_param_decorator)
  • JIT ctorParameters, the own-ctor-params check and the param identifiers it keeps imports for
  • directive param-decorator validation, which already filtered on the body and now shares the helper

Checks

  • ctor_overloads_test.rs is new and ports the ngtsc_spec case "should compile @Injectable with constructor overloads". It covers the factory for all five decorator kinds, setClassMetadata ctor params, removal of the parameter decorator, and JIT ctorParameters. All three tests fail on main.
  • cargo test -p oxc_angular_compiler --all-features: 3519 passed, 0 failed.
  • cargo fmt --check passes. cargo clippy -p oxc_angular_compiler --all-features reports no warnings on the changed lines.

🤖 Generated with Claude Code

…verload

Like ngtsc's TypeScriptReflectionHost.getConstructorParameters, factories,
setClassMetadata, JIT ctorParameters and param-decorator removal now use the
constructor with a body, so overload signatures no longer drop dependencies.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Constructor overloads: factory and metadata read the first overload, not the implementation

1 participant