fix(ivy): avoid missing imports for types that can be represented as values (#28941)

Prior to this change, TypeScript stripped out some imports in case we reference a type that can be represented as a value (for ex. classes). This fix ensures that we use correct symbol identifier, which makes TypeScript retain the necessary import statements.

PR Close #28941
This commit is contained in:
Andrew Kushnir
2019-02-22 18:06:25 -08:00
parent 91a161aa13
commit 772b24ccc3
3 changed files with 116 additions and 7 deletions

View File

@ -68,16 +68,30 @@ export class TypeScriptReflectionHost implements ReflectionHost {
}
// It's not possible to get a value expression if the parameter doesn't even have a type.
if (typeNode) {
if (typeNode && ts.isTypeReferenceNode(typeNode)) {
// It's only valid to convert a type reference to a value reference if the type actually has
// a value declaration associated with it.
let type: ts.Type|null = this.checker.getTypeFromTypeNode(typeNode);
let symbol: ts.Symbol|undefined = this.checker.getSymbolAtLocation(typeNode.typeName);
if (type && type.symbol !== undefined && type.symbol.valueDeclaration !== undefined) {
// The type points to a valid value declaration. Rewrite the TypeReference into an
// Expression
// which references the value pointed to by the TypeReference, if possible.
typeValueExpr = typeNodeToValueExpr(typeNode);
if (symbol !== undefined) {
let resolvedSymbol = symbol;
if (symbol.flags & ts.SymbolFlags.Alias) {
resolvedSymbol = this.checker.getAliasedSymbol(symbol);
}
if (resolvedSymbol.valueDeclaration !== undefined) {
// The type points to a valid value declaration. Rewrite the TypeReference into an
// Expression which references the value pointed to by the TypeReference, if possible.
const firstDecl = symbol.declarations && symbol.declarations[0];
if (firstDecl && ts.isImportSpecifier(firstDecl)) {
// Making sure TS produces the necessary imports in case a symbol was declared in a
// different script and imported. To do that we check symbol's first declaration and
// if it's an import - use its identifier. The `Identifier` from the `ImportSpecifier`
// knows it could be a value reference, and will emit as one if needed.
typeValueExpr = ts.updateIdentifier(firstDecl.name);
} else {
typeValueExpr = typeNodeToValueExpr(typeNode);
}
}
}
}