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},
|
||||
outputs: {...outputsFromMeta, ...outputsFromFields}, queries, selector,
|
||||
type: new WrappedNodeExpr(clazz.name !),
|
||||
typeArgumentCount: (clazz.typeParameters || []).length,
|
||||
typeSourceSpan: null !, usesInheritance,
|
||||
};
|
||||
return {decoratedElements, decorator: directive, metadata};
|
||||
|
|
|
@ -305,8 +305,14 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
visitExpressionType(type: ExpressionType, context: Context): any {
|
||||
return type.value.visitExpression(this, context);
|
||||
visitExpressionType(type: ExpressionType, context: Context): string {
|
||||
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 {
|
||||
|
|
|
@ -47,7 +47,11 @@ export class BuiltinType 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 {
|
||||
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); }
|
||||
visitExpressionType(type: ExpressionType, context: any): any {
|
||||
type.value.visitExpression(this, context);
|
||||
if (type.typeParams !== null) {
|
||||
type.typeParams.forEach(param => this.visitType(param, context));
|
||||
}
|
||||
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(
|
||||
expr: Expression, typeModifiers: TypeModifier[] | null = null): ExpressionType {
|
||||
return new ExpressionType(expr, typeModifiers);
|
||||
expr: Expression, typeModifiers: TypeModifier[] | null = null,
|
||||
typeParams: Type[] | null = null): ExpressionType {
|
||||
return new ExpressionType(expr, typeModifiers, typeParams);
|
||||
}
|
||||
|
||||
export function typeofExpr(expr: Expression) {
|
||||
|
|
|
@ -361,6 +361,11 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor
|
|||
|
||||
visitExpressionType(ast: o.ExpressionType, ctx: EmitterVisitorContext): any {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,3 +36,14 @@ export function convertMetaToOutput(meta: any, ctx: OutputContext): o.Expression
|
|||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Number of generic type parameters of the type itself.
|
||||
*/
|
||||
typeArgumentCount: number;
|
||||
|
||||
/**
|
||||
* A source span for the directive type.
|
||||
*/
|
||||
|
|
|
@ -20,11 +20,12 @@ import {ParseSourceSpan, typeSourceSpan} from '../../parse_util';
|
|||
import {CssSelector, SelectorMatcher} from '../../selector';
|
||||
import {BindingParser} from '../../template_parser/binding_parser';
|
||||
import {OutputContext, error} from '../../util';
|
||||
|
||||
import * as t from '../r3_ast';
|
||||
import {R3DependencyMetadata, R3ResolvedDependencyType, compileFactoryFunction, dependenciesFromGlobalMetadata} from '../r3_factory';
|
||||
import {Identifiers as R3} from '../r3_identifiers';
|
||||
import {Render3ParseResult} from '../r3_template_transform';
|
||||
import {typeWithParameters} from '../util';
|
||||
|
||||
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api';
|
||||
import {BindingScope, TemplateDefinitionBuilder} from './template';
|
||||
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.
|
||||
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
||||
|
||||
const type = new o.ExpressionType(o.importExpr(
|
||||
R3.DirectiveDef,
|
||||
[new o.ExpressionType(meta.type), new o.ExpressionType(o.literal(selectorForType))]));
|
||||
const type = new o.ExpressionType(o.importExpr(R3.DirectiveDef, [
|
||||
typeWithParameters(meta.type, meta.typeArgumentCount),
|
||||
new o.ExpressionType(o.literal(selectorForType))
|
||||
]));
|
||||
return {expression, type};
|
||||
}
|
||||
|
||||
|
@ -167,9 +169,10 @@ export function compileComponentFromMetadata(
|
|||
const selectorForType = (meta.selector || '').replace(/\n/g, '');
|
||||
|
||||
const expression = o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()]);
|
||||
const type = new o.ExpressionType(o.importExpr(
|
||||
R3.ComponentDef,
|
||||
[new o.ExpressionType(meta.type), new o.ExpressionType(o.literal(selectorForType))]));
|
||||
const type = new o.ExpressionType(o.importExpr(R3.ComponentDef, [
|
||||
typeWithParameters(meta.type, meta.typeArgumentCount),
|
||||
new o.ExpressionType(o.literal(selectorForType))
|
||||
]));
|
||||
|
||||
return {expression, type};
|
||||
}
|
||||
|
@ -252,6 +255,7 @@ function directiveMetadataFromGlobalMetadata(
|
|||
return {
|
||||
name,
|
||||
type: outputCtx.importExpr(directive.type.reference),
|
||||
typeArgumentCount: 0,
|
||||
typeSourceSpan:
|
||||
typeSourceSpan(directive.isComponent ? 'Component' : 'Directive', directive.type),
|
||||
selector: directive.selector,
|
||||
|
|
|
@ -155,6 +155,7 @@ function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMet
|
|||
return {
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
typeArgumentCount: 0,
|
||||
selector: metadata.selector !,
|
||||
deps: reflectDependencies(type), host,
|
||||
inputs: {...inputsFromMetadata, ...inputsFromType},
|
||||
|
|
Loading…
Reference in New Issue