google / google/closure-compiler
Failing to unify complex types with explicit annotation
- Dominant language
- JavaScript
- Stars
- 7.7k
- Forks
- 1.2k
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 6
Description
Closure compiler cannot unify complex types even though it seems to have enough information to do so.
``` javascript
/**
* @constructor
* @template T
* @param {T} x
*/
function Foo(x) {
this.x = x;
}
var a = new Foo('asdf');
/** @type {!Foo.} */
var b = new Foo('asdf');
/** @type {!Foo.<{a: string, b: !Foo.}>} */
var c = new Foo({a: 'foo', b: new Foo('asdf')});
```
```
casterror.js:17: WARNING - initializing variable
found : Foo<{a: string, b: Foo}>
required: Foo<{a: string, b: Foo}>
var c = new Foo({a: 'foo', b: new Foo(1)});
^
0 error(s), 1 warning(s), 94.1% typed
```
Without the explicit cast closure compiler infers the correct types (to a degree), but sometimes annotations are helpful for documentation purposes. However, not including the cast is not a work around, even though closure compiler can recognize the correct type it will not enforce it.
``` javascript
/**
* @param {!Foo.} x
* @return {number}
*/
function blat(x) {
return x.x;
}
console.log(blat(a));
console.log(blat(b));
console.log(blat(c));
console.log(blat(c.x.b));
```
```
casterror.js:28: WARNING - actual parameter 1 of blat does not match formal parameter
found : Foo
required: Foo
console.log(blat(a));
^
casterror.js:29: WARNING - actual parameter 1 of blat does not match formal parameter
found : Foo
required: Foo
console.log(blat(b));
^
casterror.js:30: WARNING - actual parameter 1 of blat does not match formal parameter
found : Foo<{a: string, b: Foo}>
required: Foo
console.log(blat(c));
```
The final call of `blat` is not caught as a type error even though the previous call shows an inferred type that should cause one.
Contributor guide
Assessment
This issue has not been assessed yet.