Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 249273f

Browse files
committed
remove function wrappers for member type declarations
To declare the types of class members, we want to emit e.g. /** @type {Foo} */ MyClass.prototype.foo; We cannot declare these in the class constructor because sometimes we don't have a constructor and it's difficult to create our own (we'd need to match the superclass in that case). We sometimes cannot declare these at the top level because it's possible there's a supertype that throws on get, which means the code cannot be loaded as written without compiling it first. (We know this actually can happen because we tried it.) In the past we declared these in a helper method or bare function, but it turns out declarations in those are ignored by Closure in unpredictable circumstances. So our final approach is: - for interfaces, declare them at the top level - for classes, wrap them in an 'if (false)' block. To do so we must suppress the 'useless code' compiler check, because putting code in an 'if (false)' is pretty suspicious looking otherwise.
1 parent d73e7fd commit 249273f

140 files changed

Lines changed: 274 additions & 351 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/fileoverview_comment_transformer.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ function augmentFileoverviewComments(tags: jsdoc.Tag[]) {
6060
// 2) Suppress extraRequire. We remove extra requires at the TypeScript level, so any require
6161
// that gets to the JS level is a load-bearing require.
6262
suppressions.add('extraRequire');
63+
// 3) Suppress uselessCode. We emit an "if (false)" around type declarations,
64+
// which is flagged as unused code unless we suppress it.
65+
suppressions.add('uselessCode');
6366
suppressTag.type = Array.from(suppressions.values()).sort().join(',');
6467

6568
return tags;

src/tsickle.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,7 @@ class Annotator extends ClosureRewriter {
12881288
if (docTags.length > 0) this.emit(jsdoc.toString(docTags));
12891289
// this.writeNode(classDecl, true /*skipComments*/);
12901290
this.writeNodeFrom(classDecl, classDecl.getStart(), classDecl.getEnd());
1291-
this.emitTypeAnnotationsHelper(classDecl);
1291+
this.emitMemberTypes(classDecl);
12921292
return true;
12931293
}
12941294

@@ -1312,23 +1312,20 @@ class Annotator extends ClosureRewriter {
13121312
const name = getIdentifierText(iface.name);
13131313
this.emit(`function ${name}() {}\n`);
13141314

1315-
this.emit(`\n\nfunction ${name}_tsickle_Closure_declarations() {\n`);
13161315
const memberNamespace = [name, 'prototype'];
13171316
for (const elem of iface.members) {
13181317
const isOptional = elem.questionToken != null;
13191318
this.visitProperty(memberNamespace, elem, isOptional);
13201319
}
1321-
this.emit(`}\n`);
13221320
}
13231321

13241322
/**
1325-
* emitTypeAnnotationsHelper produces a _tsickle_typeAnnotationsHelper() where
1326-
* none existed in the original source. It's necessary in the case where
1327-
* TypeScript syntax specifies there are additional properties on the class,
1328-
* because to declare these in Closure you must declare these in a method
1329-
* somewhere.
1323+
* emitMemberTypes emits the type annotations for members of a class.
1324+
* It's necessary in the case where TypeScript syntax specifies
1325+
* there are additional properties on the class, because to declare
1326+
* these in Closure you must declare these separately from the class.
13301327
*/
1331-
private emitTypeAnnotationsHelper(classDecl: ts.ClassDeclaration) {
1328+
private emitMemberTypes(classDecl: ts.ClassDeclaration) {
13321329
// Gather parameter properties from the constructor, if it exists.
13331330
const ctors: ts.ConstructorDeclaration[] = [];
13341331
let paramProps: ts.ParameterDeclaration[] = [];
@@ -1372,7 +1369,7 @@ class Annotator extends ClosureRewriter {
13721369
const className = getIdentifierText(classDecl.name);
13731370

13741371
// See test_files/fields/fields.ts:BaseThatThrows for a note on this wrapper.
1375-
this.emit(`\n\nfunction ${className}_tsickle_Closure_declarations() {\n`);
1372+
this.emit(`\n\nif (false) {`);
13761373
staticProps.forEach(p => this.visitProperty([className], p));
13771374
const memberNamespace = [className, 'prototype'];
13781375
nonStaticProps.forEach((p) => this.visitProperty(memberNamespace, p));

test_files/abstract/abstract.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.abstract.abstract');
66
var module = module || { id: 'test_files/abstract/abstract.ts' };
@@ -19,7 +19,7 @@ class Base {
1919
this.hasReturnType();
2020
}
2121
}
22-
function Base_tsickle_Closure_declarations() {
22+
if (false) {
2323
/**
2424
* @abstract
2525
* @return {void}

test_files/arrow_fn.es5/arrow_fn_es5.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview Reproduces an error that caused incorrect Automatic Semicolon Insertion.
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.arrow_fn.es5.arrow_fn_es5');
66
var module = module || { id: 'test_files/arrow_fn.es5/arrow_fn_es5.ts' };

test_files/arrow_fn.untyped/arrow_fn.untyped.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.arrow_fn.untyped.arrow_fn.untyped');
66
var module = module || { id: 'test_files/arrow_fn.untyped/arrow_fn.untyped.ts' };

test_files/arrow_fn/arrow_fn.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.arrow_fn.arrow_fn');
66
var module = module || { id: 'test_files/arrow_fn/arrow_fn.ts' };

test_files/basic.untyped/basic.untyped.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.basic.untyped.basic.untyped');
66
var module = module || { id: 'test_files/basic.untyped/basic.untyped.ts' };
@@ -20,7 +20,7 @@ class Foo {
2020
this.field = 'hello';
2121
}
2222
}
23-
function Foo_tsickle_Closure_declarations() {
23+
if (false) {
2424
/** @type {?} */
2525
Foo.prototype.field;
2626
/** @type {?} */

test_files/class.untyped/class.js

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.class.untyped.class');
66
var module = module || { id: 'test_files/class.untyped/class.ts' };
77
/**
88
* @record
99
*/
1010
function Interface() { }
11-
function Interface_tsickle_Closure_declarations() {
12-
/** @type {?} */
13-
Interface.prototype.interfaceFunc;
14-
}
11+
/** @type {?} */
12+
Interface.prototype.interfaceFunc;
1513
class Super {
1614
/**
1715
* @return {?}
@@ -62,15 +60,15 @@ superVar = new ImplementsTypeAlias();
6260
function Zone() { }
6361
class ZoneImplementsInterface {
6462
}
65-
function ZoneImplementsInterface_tsickle_Closure_declarations() {
63+
if (false) {
6664
/** @type {?} */
6765
ZoneImplementsInterface.prototype.zone;
6866
}
6967
/** @typedef {?} */
7068
var ZoneAlias;
7169
class ZoneImplementsAlias {
7270
}
73-
function ZoneImplementsAlias_tsickle_Closure_declarations() {
71+
if (false) {
7472
/** @type {?} */
7573
ZoneImplementsAlias.prototype.zone;
7674
}

test_files/class/class.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// test_files/class/class.ts(129,1): warning TS0: type/symbol conflict for Zone, using {?} for now
22
/**
33
* @fileoverview added by tsickle
4-
* @suppress {checkTypes,extraRequire} checked by tsc
4+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
55
*/
66
// This test exercises the various ways classes and interfaces can interact.
77
// There are three types of classy things:
@@ -17,10 +17,8 @@ var module = module || { id: 'test_files/class/class.ts' };
1717
* @record
1818
*/
1919
function Interface() { }
20-
function Interface_tsickle_Closure_declarations() {
21-
/** @type {function(): void} */
22-
Interface.prototype.interfaceFunc;
23-
}
20+
/** @type {function(): void} */
21+
Interface.prototype.interfaceFunc;
2422
class Class {
2523
/**
2624
* @return {void}
@@ -36,7 +34,7 @@ class AbstractClass {
3634
*/
3735
nonAbstractFunc() { }
3836
}
39-
function AbstractClass_tsickle_Closure_declarations() {
37+
if (false) {
4038
/**
4139
* @abstract
4240
* @return {void}
@@ -48,10 +46,8 @@ function AbstractClass_tsickle_Closure_declarations() {
4846
* @extends {Interface}
4947
*/
5048
function InterfaceExtendsInterface() { }
51-
function InterfaceExtendsInterface_tsickle_Closure_declarations() {
52-
/** @type {function(): void} */
53-
InterfaceExtendsInterface.prototype.interfaceFunc2;
54-
}
49+
/** @type {function(): void} */
50+
InterfaceExtendsInterface.prototype.interfaceFunc2;
5551
/** @type {!InterfaceExtendsInterface} */
5652
let interfaceExtendsInterface = {
5753
/**
@@ -67,10 +63,8 @@ let interfaceExtendsInterface = {
6763
* @record
6864
*/
6965
function InterfaceExtendsClass() { }
70-
function InterfaceExtendsClass_tsickle_Closure_declarations() {
71-
/** @type {function(): void} */
72-
InterfaceExtendsClass.prototype.interfaceFunc3;
73-
}
66+
/** @type {function(): void} */
67+
InterfaceExtendsClass.prototype.interfaceFunc3;
7468
/**
7569
* @implements {Interface}
7670
*/
@@ -198,15 +192,15 @@ abstractClassVar = new ClassExtendsAbstractClass();
198192
function Zone() { }
199193
class ZoneImplementsInterface {
200194
}
201-
function ZoneImplementsInterface_tsickle_Closure_declarations() {
195+
if (false) {
202196
/** @type {string} */
203197
ZoneImplementsInterface.prototype.zone;
204198
}
205199
/** @typedef {?} */
206200
var ZoneAlias;
207201
class ZoneImplementsAlias {
208202
}
209-
function ZoneImplementsAlias_tsickle_Closure_declarations() {
203+
if (false) {
210204
/** @type {string} */
211205
ZoneImplementsAlias.prototype.zone;
212206
}

test_files/clutz.no_externs/strip_clutz_type.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @fileoverview added by tsickle
3-
* @suppress {checkTypes,extraRequire} checked by tsc
3+
* @suppress {checkTypes,extraRequire,uselessCode} checked by tsc
44
*/
55
goog.module('test_files.clutz.no_externs.strip_clutz_type');
66
var module = module || { id: 'test_files/clutz.no_externs/strip_clutz_type.ts' };

0 commit comments

Comments
 (0)