Skip to content

Commit 15e87f0

Browse files
committed
emit types with their namespace
Summary: If you import a type from another module, when emitting the type in Closure-land you also need to qualify it with its module name. This is the first step towards solving #112. This is the easy but necessary part; further changes will add the harder cases. Reviewers: rkirov Reviewed By: rkirov Subscribers: typescript-eng Differential Revision: https://reviews.angular.io/D125
1 parent 9b4d274 commit 15e87f0

10 files changed

+73
-6
lines changed

src/type-translator.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,41 @@ export class TypeTranslator {
6767
*/
6868
constructor(private typeChecker: ts.TypeChecker, private node: ts.Node) {}
6969

70+
/**
71+
* Converts a ts.Symbol to a string.
72+
* Other approaches that don't work:
73+
* - TypeChecker.typeToString translates Array as T[].
74+
* - TypeChecker.symbolToString emits types without their namespace,
75+
* and doesn't let you pass the flag to control that.
76+
*/
77+
private symbolToString(sym: ts.Symbol): string {
78+
// This follows getSingleLineStringWriter in the TypeScript compiler.
79+
let str = '';
80+
let writeText = (text: string) => str += text;
81+
let doNothing = () => { return; };
82+
83+
let builder = this.typeChecker.getSymbolDisplayBuilder();
84+
let writer: ts.SymbolWriter = {
85+
writeKeyword: writeText,
86+
writeOperator: writeText,
87+
writePunctuation: writeText,
88+
writeSpace: writeText,
89+
writeStringLiteral: writeText,
90+
writeParameter: writeText,
91+
writeSymbol: writeText,
92+
writeLine: doNothing,
93+
increaseIndent: doNothing,
94+
decreaseIndent: doNothing,
95+
clear: doNothing,
96+
trackSymbol(symbol: ts.Symbol, enclosingDeclaration?: ts.Node, meaning?: ts.SymbolFlags) {
97+
return;
98+
},
99+
reportInaccessibleThisError: doNothing,
100+
};
101+
builder.buildSymbolDisplay(sym, writer, this.node);
102+
return str;
103+
}
104+
70105
/**
71106
* @param notNull When true, insert a ! before any type references. This
72107
* is to work around the difference between TS and Closure destructuring.
@@ -112,7 +147,7 @@ export class TypeTranslator {
112147
// InterfaceType "Array", but the "number" type parameter is
113148
// part of the outer TypeReference, not a typeParameter on
114149
// the InterfaceType.
115-
return type.symbol.name;
150+
return this.symbolToString(type.symbol);
116151
} else if (type.flags & ts.TypeFlags.Reference) {
117152
// A reference to another type, e.g. Array<number> refers to Array.
118153
// Emit the referenced type and any type arguments.

test_files/jsdoc_types/jsdoc_types.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
goog.module('tsickle_test.jsdoc_types.jsdoc_types');/**
2+
* This test tests importing a type across module boundaries,
3+
* ensuring that the type gets the proper name in JSDoc comments.
4+
*/
5+
6+
var module1 = goog.require('tsickle_test.jsdoc_types.module1');
7+
// Check that imported types get the proper names in JSDoc.
8+
let /** @type {module1.Class} */ x1 = new module1.Class();

test_files/jsdoc_types/jsdoc_types.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* This test tests importing a type across module boundaries,
3+
* ensuring that the type gets the proper name in JSDoc comments.
4+
*/
5+
6+
import * as module1 from './module1';
7+
8+
// Check that imported types get the proper names in JSDoc.
9+
let x1 = new module1.Class();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* This test tests importing a type across module boundaries,
3+
* ensuring that the type gets the proper name in JSDoc comments.
4+
*/
5+
6+
import * as module1 from './module1';
7+
8+
// Check that imported types get the proper names in JSDoc.
9+
let /** @type {module1.Class} */ x1 = new module1.Class();

test_files/jsdoc_types/module1.js

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
goog.module('tsickle_test.jsdoc_types.module1');
2+
class Class {
3+
}
4+
exports.Class = Class;

test_files/jsdoc_types/module1.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export class Class {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export class Class {}

test_files/jsx/externs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var React = {};
1717
React.createElement = function(args) {};
1818

1919
/**
20-
* @param {Element} element
20+
* @param {JSX.Element} element
2121
* @param {HTMLElement} node
2222
* @return {void}
2323
*/

test_files/jsx/jsx.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
goog.module('tsickle_test.jsx.jsx');let /** @type {Element} */ simple = React.createElement("div", null);
1+
goog.module('tsickle_test.jsx.jsx');let /** @type {JSX.Element} */ simple = React.createElement("div", null);
22
let /** @type {string} */ hello = 'hello';
3-
let /** @type {Element} */ helloDiv = React.createElement("div", null, hello, "hello, world", React.createElement(Component, null));
3+
let /** @type {JSX.Element} */ helloDiv = React.createElement("div", null, hello, "hello, world", React.createElement(Component, null));
44
React.render(helloDiv, document.body);

test_files/jsx/jsx.tsickle.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ declare module React {
1616
// Fake a subcomponent, just to exercise components within components.
1717
declare var Component: any;
1818

19-
let /** @type {Element} */ simple = <div></div>;
19+
let /** @type {JSX.Element} */ simple = <div></div>;
2020

2121
let /** @type {string} */ hello = 'hello';
22-
let /** @type {Element} */ helloDiv = <div>
22+
let /** @type {JSX.Element} */ helloDiv = <div>
2323
{hello}
2424
hello, world
2525
<Component/>

0 commit comments

Comments
 (0)