closure-compiler
closure-compiler copied to clipboard
`@type` doesn't work on functions when a forward reference or requireType'd
Inline Case (working)
This has the typedef inline in a single file:
/**
* @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:
// typedef.js
goog.module('Foo');
/**
* @typedef {function(!string, number):string}
*/
let Foo;
exports = Foo;
// 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)
// typedef.js
goog.provide('Foo');
/**
* @typedef {function(!string, number):string}
*/
Foo;
// 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