fix(ivy): include type parameter for `ngBaseDef` declaration (#31210)
When a class uses Angular decorators such as `@Input`, `@Output` and friends without an Angular class decorator, they are compiled into a static `ngBaseDef` field on the class, with the TypeScript declaration of the class being altered to declare the `ngBaseDef` field to be of type `ɵɵBaseDef`. This type however requires a generic type parameter that corresponds with the type of the class, however the compiler did not provide this type parameter. As a result, compiling a program where such invalid `ngBaseDef` declarations are present will result in compilation errors. This commit fixes the problem by providing the generic type parameter. Fixes #31160 PR Close #31210
This commit is contained in:
parent
a4a423a083
commit
eb6281f5b4
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ConstantPool, R3BaseRefMetaData, compileBaseDefFromMetadata, makeBindingParser} from '@angular/compiler';
|
||||
import {ConstantPool, R3BaseRefMetaData, WrappedNodeExpr, compileBaseDefFromMetadata, makeBindingParser} from '@angular/compiler';
|
||||
|
||||
import {PartialEvaluator} from '../../partial_evaluator';
|
||||
import {ClassDeclaration, ClassMember, Decorator, ReflectionHost} from '../../reflection';
|
||||
|
@ -91,7 +91,11 @@ export class BaseDefDecoratorHandler implements
|
|||
|
||||
analyze(node: ClassDeclaration, metadata: R3BaseRefDecoratorDetection):
|
||||
AnalysisOutput<R3BaseRefMetaData> {
|
||||
const analysis: R3BaseRefMetaData = {name: node.name.text, typeSourceSpan: null !};
|
||||
const analysis: R3BaseRefMetaData = {
|
||||
name: node.name.text,
|
||||
type: new WrappedNodeExpr(node.name),
|
||||
typeSourceSpan: null !
|
||||
};
|
||||
|
||||
if (metadata.inputs) {
|
||||
const inputs = analysis.inputs = {} as{[key: string]: string | [string, string]};
|
||||
|
|
|
@ -423,6 +423,24 @@ runInEachFileSystem(os => {
|
|||
expect(jsContents).toContain('background-color: blue');
|
||||
});
|
||||
|
||||
it('should include generic type for ngBaseDef declarations', () => {
|
||||
env.write('test.ts', `
|
||||
import {Component, Input, NgModule} from '@angular/core';
|
||||
|
||||
export class TestBase {
|
||||
@Input() input: any;
|
||||
}
|
||||
`);
|
||||
|
||||
env.driveMain();
|
||||
|
||||
const jsContents = env.getContents('test.js');
|
||||
expect(jsContents).toContain('i0.ɵɵdefineBase({ inputs: { input: "input" } });');
|
||||
|
||||
const dtsContents = env.getContents('test.d.ts');
|
||||
expect(dtsContents).toContain('static ngBaseDef: i0.ɵɵBaseDef<TestBase>');
|
||||
});
|
||||
|
||||
it('should compile NgModules without errors', () => {
|
||||
env.write('test.ts', `
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
|
|
|
@ -151,6 +151,7 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
|
|||
|
||||
export interface R3BaseMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
propMetadata: {[key: string]: any[]};
|
||||
inputs?: {[key: string]: string | [string, string]};
|
||||
outputs?: {[key: string]: string};
|
||||
|
|
|
@ -142,6 +142,7 @@ export function compileDirectiveFromMetadata(
|
|||
|
||||
export interface R3BaseRefMetaData {
|
||||
name: string;
|
||||
type: o.Expression;
|
||||
typeSourceSpan: ParseSourceSpan;
|
||||
inputs?: {[key: string]: string | [string, string]};
|
||||
outputs?: {[key: string]: string};
|
||||
|
@ -188,7 +189,8 @@ export function compileBaseDefFromMetadata(
|
|||
}
|
||||
|
||||
const expression = o.importExpr(R3.defineBase).callFn([definitionMap.toLiteralMap()]);
|
||||
const type = new o.ExpressionType(o.importExpr(R3.BaseDef));
|
||||
const type = new o.ExpressionType(
|
||||
o.importExpr(R3.BaseDef), /* modifiers */ null, [o.expressionType(meta.type)]);
|
||||
|
||||
return {expression, type};
|
||||
}
|
||||
|
|
|
@ -151,6 +151,7 @@ export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
|
|||
|
||||
export interface R3BaseMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
propMetadata: {[key: string]: any[]};
|
||||
inputs?: {[key: string]: string | [string, string]};
|
||||
outputs?: {[key: string]: string};
|
||||
|
|
|
@ -241,7 +241,7 @@ function extractBaseDefMetadata(type: Type<any>): R3BaseMetadataFacade|null {
|
|||
|
||||
// Only generate the base def if there's any info inside it.
|
||||
if (inputs || outputs || viewQueries.length || queries.length || hasHostDecorators) {
|
||||
return {name: type.name, inputs, outputs, viewQueries, queries, propMetadata};
|
||||
return {name: type.name, type, inputs, outputs, viewQueries, queries, propMetadata};
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
Loading…
Reference in New Issue