diff --git a/packages/compiler-cli/src/ngtsc/annotations/common/src/diagnostics.ts b/packages/compiler-cli/src/ngtsc/annotations/common/src/diagnostics.ts index b41b7fbbac6bd..5afd006f57bbf 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/common/src/diagnostics.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/common/src/diagnostics.ts @@ -14,7 +14,7 @@ import {DirectiveMeta, flattenInheritedDirectiveMetadata, HostDirectiveMeta, Met import {describeResolvedType, DynamicValue, PartialEvaluator, ResolvedValue, traceDynamicValue} from '../../../partial_evaluator'; import {ClassDeclaration, ReflectionHost} from '../../../reflection'; import {DeclarationData, LocalModuleScopeRegistry} from '../../../scope'; -import {identifierOfNode} from '../../../util/src/typescript'; +import {identifierOfNode, isFromDtsFile} from '../../../util/src/typescript'; import {InjectableClassRegistry} from './injectable_registry'; import {isAbstractClassDeclaration, readBaseClass} from './util'; @@ -256,6 +256,14 @@ export function checkInheritanceOfInjectable( return getInheritedUndecoratedCtorDiagnostic(node, classWithCtor.ref, kind); } + if (isFromDtsFile(classWithCtor.ref.node)) { + // The inherited class is declared in a declaration file, in which case there is not enough + // information to detect invalid constructors as `@Inject()` metadata is not present in the + // declaration file. Consequently, we have to accept such occurrences, although they might + // still fail at runtime. + return null; + } + if (!strictInjectionParameters || isAbstractClassDeclaration(node)) { // An invalid constructor is only reported as error under `strictInjectionParameters` and // only for concrete classes; follow the same exclusions for derived types. diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index c43f13c4d58c7..68d9c1ead3885 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -2960,6 +2960,37 @@ function allTests(os: string) { `or add an explicit constructor to ConcreteDirWithoutCtor.`); expect(getDiagnosticSourceCode(diags[2])).toBe('ConcreteDirWithoutCtor'); }); + + // https://github.com/angular/angular/issues/48152 + it('should not give a compile-time error when a class inherits from foreign compilation unit', + () => { + env.tsconfig({strictInjectionParameters: true}); + env.write('node_modules/external/index.d.ts', ` + import * as i0 from '@angular/core'; + + export abstract class ExternalClass { + static ɵprov: i0.ɵɵInjectableDeclaration; + static ɵfac: i0.ɵɵFactoryDeclaration + + constructor(invalid: string) {} + } + `); + env.write('test.ts', ` + import {Directive} from '@angular/core'; + import {ExternalClass} from 'external'; + + @Directive() + export abstract class AbstractMiddleDir extends ExternalClass {} + + @Directive() + export class ConcreteMiddleDir extends AbstractMiddleDir {} + + @Directive() + export class ConcreteDirWithoutCtor extends ConcreteMiddleDir {} + `); + + env.driveMain(); + }); }); describe('with strictInjectionParameters = false', () => {