google / google/closure-compiler
`@type` doesn't work on functions when a forward reference or requireType'd
- Dominant language
- JavaScript
- Stars
- 7.7k
- Forks
- 1.2k
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 6
Description
## Inline Case (working)
This has the typedef inline in a single file:
```javascript
/**
* @typedef {function(!string, number):string}
*/
let Foo;
/**
* @type {Foo}
*/
const impl = (foo, bar) => [foo]; // incorrectly returns an array
const result = impl('test', 1);
impl(result, 2);
```
Compiler Args:
```
java -jar node_modules/google-closure-compiler-java/compiler.jar --dependency_mode=PRUNE --language_in=ECMASCRIPT_2018 --warning_level=VERBOSE --jscomp_error=accessControls --jscomp_error=checkPrototypalTypes --jscomp_error=checkRegExp --jscomp_error=checkTypes --jscomp_error=checkVars --jscomp_error=conformanceViolations --jscomp_error=const --jscomp_error=constantProperty --jscomp_error=deprecatedAnnotations --jscomp_error=duplicateMessage --jscomp_error=es5Strict --jscomp_error=externsValidation --jscomp_error=functionParams --jscomp_error=globalThis --jscomp_error=invalidCasts --jscomp_error=misplacedTypeAnnotation --jscomp_error=missingGetCssName --jscomp_error=missingOverride --jscomp_error=missingPolyfill --jscomp_error=missingProperties --jscomp_error=missingProvide --jscomp_error=missingRequire --jscomp_error=missingReturn --jscomp_error=missingSourcesWarnings --jscomp_error=moduleLoad --jscomp_error=msgDescriptions --jscomp_error=nonStandardJsDocs --jscomp_error=partialAlias --jscomp_error=polymer --jscomp_error=strictModuleDepCheck --jscomp_error=strictPrimitiveOperators --jscomp_error=suspiciousCode --jscomp_error=typeInvalidation --jscomp_error=undefinedNames --jscomp_error=undefinedVars --jscomp_error=underscore --jscomp_error=unknownDefines --jscomp_error=unusedLocalVariables --jscomp_error=unusedPrivateMembers --jscomp_error=useOfGoogBase --jscomp_error=uselessCode --jscomp_error=untranspilableFeatures --jscomp_error=visibility --jscomp_warning=deprecated --jscomp_off=reportUnknownTypes --jscomp_off=strictCheckTypes --jscomp_off=strictMissingProperties --compilation_level=ADVANCED --js_output_file=output.js --js input.js --entry_point input.js
```
Result:
```
input.js:9: ERROR - [JSC_TYPE_MISMATCH] inconsistent return type
found : Array
required: string
const impl = (foo, bar) => [foo]; // incorrectly returns an array
^^^^^
1 error(s), 0 warning(s), 100.0% typed
```
That's all well and good as expected.
## Goog Module Case (broken)
Using `goog.module` results in the error not occurring:
```javascript
// typedef.js
goog.module('Foo');
/**
* @typedef {function(!string, number):string}
*/
let Foo;
exports = Foo;
```
```javascript
// input.js
goog.module('test');
const Foo = goog.requireType('Foo');
/**
* @type {Foo}
*/
const impl = (foo, bar) => [foo]; // incorrectly returns an array
const result = impl('test', 1);
impl(result, 2);
```
Compiler Args:
```
java -jar node_modules/google-closure-compiler-java/compiler.jar --dependency_mode=PRUNE --language_in=ECMASCRIPT_2018 --warning_level=VERBOSE --jscomp_error=accessControls --jscomp_error=checkPrototypalTypes --jscomp_error=checkRegExp --jscomp_error=checkTypes --jscomp_error=checkVars --jscomp_error=conformanceViolations --jscomp_error=const --jscomp_error=constantProperty --jscomp_error=deprecatedAnnotations --jscomp_error=duplicateMessage --jscomp_error=es5Strict --jscomp_error=externsValidation --jscomp_error=functionParams --jscomp_error=globalThis --jscomp_error=invalidCasts --jscomp_error=misplacedTypeAnnotation --jscomp_error=missingGetCssName --jscomp_error=missingOverride --jscomp_error=missingPolyfill --jscomp_error=missingProperties --jscomp_error=missingProvide --jscomp_error=missingRequire --jscomp_error=missingReturn --jscomp_error=missingSourcesWarnings --jscomp_error=moduleLoad --jscomp_error=msgDescriptions --jscomp_error=nonStandardJsDocs --jscomp_error=partialAlias --jscomp_error=polymer --jscomp_error=strictModuleDepCheck --jscomp_error=strictPrimitiveOperators --jscomp_error=suspiciousCode --jscomp_error=typeInvalidation --jscomp_error=undefinedNames --jscomp_error=undefinedVars --jscomp_error=underscore --jscomp_error=unknownDefines --jscomp_error=unusedLocalVariables --jscomp_error=unusedPrivateMembers --jscomp_error=useOfGoogBase --jscomp_error=uselessCode --jscomp_error=untranspilableFeatures --jscomp_error=visibility --jscomp_warning=deprecated --jscomp_off=reportUnknownTypes --jscomp_off=strictCheckTypes --jscomp_off=strictMissingProperties --compilation_level=ADVANCED --js_output_file=output.js --js input.js --js typedef.js '--js=!node_modules/google-closure-library/closure/goog/**test.js' '--js=!node_modules/google-closure-library/third_party/**test.js' '--js=node_modules/google-closure-library/closure/goog/**.js' '--js=node_modules/google-closure-library/third_party/**.js' --hide_warnings_for=/google-closure-library/ --entry_point input.js
```
Result: No errors.
Expected result: Same error as above
## Goog Provide Case (different result)
```javascript
// typedef.js
goog.provide('Foo');
/**
* @typedef {function(!string, number):string}
*/
Foo;
```
```javascript
// input.js
goog.require('Foo');
/**
* @type {!Foo}
*/
const impl = (foo, bar) => [foo]; // incorrectly returns an array
const result = impl('test', 1);
impl(result, 2);
```
Compiler Args:
```
java -jar node_modules/google-closure-compiler-java/compiler.jar --dependency_mode=PRUNE --language_in=ECMASCRIPT_2018 --warning_level=VERBOSE --jscomp_error=accessControls --jscomp_error=checkPrototypalTypes --jscomp_error=checkRegExp --jscomp_error=checkTypes --jscomp_error=checkVars --jscomp_error=conformanceViolations --jscomp_error=const --jscomp_error=constantProperty --jscomp_error=deprecatedAnnotations --jscomp_error=duplicateMessage --jscomp_error=es5Strict --jscomp_error=externsValidation --jscomp_error=functionParams --jscomp_error=globalThis --jscomp_error=invalidCasts --jscomp_error=misplacedTypeAnnotation --jscomp_error=missingGetCssName --jscomp_error=missingOverride --jscomp_error=missingPolyfill --jscomp_error=missingProperties --jscomp_error=missingProvide --jscomp_error=missingRequire --jscomp_error=missingReturn --jscomp_error=missingSourcesWarnings --jscomp_error=moduleLoad --jscomp_error=msgDescriptions --jscomp_error=nonStandardJsDocs --jscomp_error=partialAlias --jscomp_error=polymer --jscomp_error=strictModuleDepCheck --jscomp_error=strictPrimitiveOperators --jscomp_error=suspiciousCode --jscomp_error=typeInvalidation --jscomp_error=undefinedNames --jscomp_error=undefinedVars --jscomp_error=underscore --jscomp_error=unknownDefines --jscomp_error=unusedLocalVariables --jscomp_error=unusedPrivateMembers --jscomp_error=useOfGoogBase --jscomp_error=uselessCode --jscomp_error=untranspilableFeatures --jscomp_error=visibility --jscomp_warning=deprecated --jscomp_off=reportUnknownTypes --jscomp_off=strictCheckTypes --jscomp_off=strictMissingProperties --compilation_level=ADVANCED --js_output_file=output.js --js input.js --js typedef.js '--js=!node_modules/google-closure-library/closure/goog/**test.js' '--js=!node_modules/google-closure-library/third_party/**test.js' '--js=node_modules/google-closure-library/closure/goog/**.js' '--js=node_modules/google-closure-library/third_party/**.js' --hide_warnings_for=/google-closure-library/ --entry_point input.js
```
Result:
```
input.js:6: ERROR - [JSC_TYPE_MISMATCH] initializing variable
found : function(?, ?): ?
required: NoResolvedType
const impl = (foo, bar) => [foo]; // incorrectly returns an array
^^^^^^^^^^^^^^^^^^^
```
Expected result: Same error as inline case
I also noticed that if I move the `@type` annotation to the function expression that the compiler errors indicating that `@type` is not supported on functions. Is the only solution to this to copy/paste the full function definition everywhere or is there a better alternative?
Also, this may be related to #3041 but I was unsure.
compiler version: 20200204.0.0
library version: 20200204.0.0
Contributor guide
Assessment
This issue has not been assessed yet.