fix(ivy): types in .d.ts files should account for generics (#24862)
Ivy definition types have a generic type which specifies the return type of the factory function. For example: static ngDirectiveDef<NgForOf, '[ngFor][ngForOf]'> However, in this case NgForOf itself has a type parameter <T>. Thus, writing the above is incorrect. This commit modifies ngtsc to understand the genericness of NgForOf and to write the following: static ngDirectiveDef<NgForOf<any>, '[ngFor][ngForOf]'> PR Close #24862
This commit is contained in:
parent
2b8b647006
commit
41ef75869c
|
@ -143,6 +143,7 @@ export function extractDirectiveMetadata(
|
||||||
inputs: {...inputsFromMeta, ...inputsFromFields},
|
inputs: {...inputsFromMeta, ...inputsFromFields},
|
||||||
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, selector,
|
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, selector,
|
||||||
type: new WrappedNodeExpr(clazz.name !),
|
type: new WrappedNodeExpr(clazz.name !),
|
||||||
|
typeArgumentCount: (clazz.typeParameters || []).length,
|
||||||
typeSourceSpan: null !, usesInheritance,
|
typeSourceSpan: null !, usesInheritance,
|
||||||
};
|
};
|
||||||
return {decoratedElements, decorator: directive, metadata};
|
return {decoratedElements, decorator: directive, metadata};
|
||||||
|
|
|
@ -305,8 +305,14 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visitExpressionType(type: ExpressionType, context: Context): any {
|
visitExpressionType(type: ExpressionType, context: Context): string {
|
||||||
return type.value.visitExpression(this, context);
|
const exprStr = type.value.visitExpression(this, context);
|
||||||
|
if (type.typeParams !== null) {
|
||||||
|
const typeSegments = type.typeParams.map(param => param.visitType(this, context));
|
||||||
|
return `${exprStr}<${typeSegments.join(',')}>`;
|
||||||
|
} else {
|
||||||
|
return exprStr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visitArrayType(type: ArrayType, context: Context): string {
|
visitArrayType(type: ArrayType, context: Context): string {
|
||||||
|
|
|
@ -47,7 +47,11 @@ export class BuiltinType extends Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ExpressionType extends Type {
|
export class ExpressionType extends Type {
|
||||||
constructor(public value: Expression, modifiers: TypeModifier[]|null = null) { super(modifiers); }
|
constructor(
|
||||||
|
public value: Expression, modifiers: TypeModifier[]|null = null,
|
||||||
|
public typeParams: Type[]|null = null) {
|
||||||
|
super(modifiers);
|
||||||
|
}
|
||||||
visitType(visitor: TypeVisitor, context: any): any {
|
visitType(visitor: TypeVisitor, context: any): any {
|
||||||
return visitor.visitExpressionType(this, context);
|
return visitor.visitExpressionType(this, context);
|
||||||
}
|
}
|
||||||
|
@ -1240,6 +1244,9 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor
|
||||||
visitBuiltinType(type: BuiltinType, context: any): any { return this.visitType(type, context); }
|
visitBuiltinType(type: BuiltinType, context: any): any { return this.visitType(type, context); }
|
||||||
visitExpressionType(type: ExpressionType, context: any): any {
|
visitExpressionType(type: ExpressionType, context: any): any {
|
||||||
type.value.visitExpression(this, context);
|
type.value.visitExpression(this, context);
|
||||||
|
if (type.typeParams !== null) {
|
||||||
|
type.typeParams.forEach(param => this.visitType(param, context));
|
||||||
|
}
|
||||||
return this.visitType(type, context);
|
return this.visitType(type, context);
|
||||||
}
|
}
|
||||||
visitArrayType(type: ArrayType, context: any): any { return this.visitType(type, context); }
|
visitArrayType(type: ArrayType, context: any): any { return this.visitType(type, context); }
|
||||||
|
@ -1496,8 +1503,9 @@ export function importType(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function expressionType(
|
export function expressionType(
|
||||||
expr: Expression, typeModifiers: TypeModifier[] | null = null): ExpressionType {
|
expr: Expression, typeModifiers: TypeModifier[] | null = null,
|
||||||
return new ExpressionType(expr, typeModifiers);
|
typeParams: Type[] | null = null): ExpressionType {
|
||||||
|
return new ExpressionType(expr, typeModifiers, typeParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function typeofExpr(expr: Expression) {
|
export function typeofExpr(expr: Expression) {
|
||||||
|
|
|
@ -361,6 +361,11 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
||||||
|
|
||||||
visitExpressionType(ast: o.ExpressionType, ctx: EmitterVisitorContext): any {
|
visitExpressionType(ast: o.ExpressionType, ctx: EmitterVisitorContext): any {
|
||||||
ast.value.visitExpression(this, ctx);
|
ast.value.visitExpression(this, ctx);
|
||||||
|
if (ast.typeParams !== null) {
|
||||||
|
ctx.print(null, '<');
|
||||||
|
this.visitAllObjects(type => this.visitType(type, ctx), ast.typeParams, ctx, ',');
|
||||||
|
ctx.print(null, '>');
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,3 +36,14 @@ export function convertMetaToOutput(meta: any, ctx: OutputContext): o.Expression
|
||||||
|
|
||||||
throw new Error(`Internal error: Unsupported or unknown metadata: ${meta}`);
|
throw new Error(`Internal error: Unsupported or unknown metadata: ${meta}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function typeWithParameters(type: o.Expression, numParams: number): o.ExpressionType {
|
||||||
|
let params: o.Type[]|null = null;
|
||||||
|
if (numParams > 0) {
|
||||||
|
params = [];
|
||||||
|
for (let i = 0; i < numParams; i++) {
|
||||||
|
params.push(o.DYNAMIC_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return o.expressionType(type, null, params);
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ export interface R3DirectiveMetadata {
|
||||||
*/
|
*/
|
||||||
type: o.Expression;
|
type: o.Expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of generic type parameters of the type itself.
|
||||||
|
*/
|
||||||
|
typeArgumentCount: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A source span for the directive type.
|
* A source span for the directive type.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,11 +20,12 @@ import {ParseSourceSpan, typeSourceSpan} from '../../parse_util';
|
||||||
import {CssSelector, SelectorMatcher} from '../../selector';
|
import {CssSelector, SelectorMatcher} from '../../selector';
|
||||||
import {BindingParser} from '../../template_parser/binding_parser';
|
import {BindingParser} from '../../template_parser/binding_parser';
|
||||||
import {OutputContext, error} from '../../util';
|
import {OutputContext, error} from '../../util';
|
||||||
|
|
||||||
import * as t from '../r3_ast';
|
import * as t from '../r3_ast';
|
||||||
import {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory';
|
import {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory';
|
||||||
import {Identifiers as R3} from '../r3_identifiers';
|
import {Identifiers as R3} from '../r3_identifiers';
|
||||||
import {Render3ParseResult} from '../r3_template_transform';
|
import {Render3ParseResult} from '../r3_template_transform';
|
||||||
|
import {typeWithParameters} from '../util';
|
||||||
|
|
||||||
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api';
|
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api';
|
||||||
import {BindingScope, TemplateDefinitionBuilder} from './template';
|
import {BindingScope, TemplateDefinitionBuilder} from './template';
|
||||||
import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util';
|
import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util';
|
||||||
|
@ -93,9 +94,10 @@ export function compileDirectiveFromMetadata(
|
||||||
// string literal, which must be on one line.
|
// string literal, which must be on one line.
|
||||||
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
||||||
|
|
||||||
const type = new o.ExpressionType(o.importExpr(
|
const type = new o.ExpressionType(o.importExpr(R3.DirectiveDef, [
|
||||||
R3.DirectiveDef,
|
typeWithParameters(meta.type, meta.typeArgumentCount),
|
||||||
[new o.ExpressionType(meta.type), new o.ExpressionType(o.literal(selectorForType))]));
|
new o.ExpressionType(o.literal(selectorForType))
|
||||||
|
]));
|
||||||
return {expression, type};
|
return {expression, type};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +169,10 @@ export function compileComponentFromMetadata(
|
||||||
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
||||||
|
|
||||||
const expression = o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()]);
|
const expression = o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()]);
|
||||||
const type = new o.ExpressionType(o.importExpr(
|
const type = new o.ExpressionType(o.importExpr(R3.ComponentDef, [
|
||||||
R3.ComponentDef,
|
typeWithParameters(meta.type, meta.typeArgumentCount),
|
||||||
[new o.ExpressionType(meta.type), new o.ExpressionType(o.literal(selectorForType))]));
|
new o.ExpressionType(o.literal(selectorForType))
|
||||||
|
]));
|
||||||
|
|
||||||
return {expression, type};
|
return {expression, type};
|
||||||
}
|
}
|
||||||
|
@ -252,6 +255,7 @@ function directiveMetadataFromGlobalMetadata(
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
type: outputCtx.importExpr(directive.type.reference),
|
type: outputCtx.importExpr(directive.type.reference),
|
||||||
|
typeArgumentCount: 0,
|
||||||
typeSourceSpan:
|
typeSourceSpan:
|
||||||
typeSourceSpan(directive.isComponent ? 'Component' : 'Directive', directive.type),
|
typeSourceSpan(directive.isComponent ? 'Component' : 'Directive', directive.type),
|
||||||
selector: directive.selector,
|
selector: directive.selector,
|
||||||
|
|
|
@ -155,6 +155,7 @@ function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMet
|
||||||
return {
|
return {
|
||||||
name: type.name,
|
name: type.name,
|
||||||
type: new WrappedNodeExpr(type),
|
type: new WrappedNodeExpr(type),
|
||||||
|
typeArgumentCount: 0,
|
||||||
selector: metadata.selector !,
|
selector: metadata.selector !,
|
||||||
deps: reflectDependencies(type), host,
|
deps: reflectDependencies(type), host,
|
||||||
inputs: {...inputsFromMetadata, ...inputsFromType},
|
inputs: {...inputsFromMetadata, ...inputsFromType},
|
||||||
|
|
Loading…
Reference in New Issue