Use jsdoc casts (#17251)

* Allow jsdoc casts of parenthesized expressions

* Feedback from #17211
This commit is contained in:
Wesley Wigham
2017-07-17 23:39:20 -07:00
committed by GitHub
parent de9a67f2f3
commit 8a1cd33451
6 changed files with 382 additions and 7 deletions

View File

@@ -0,0 +1,129 @@
tests/cases/conformance/jsdoc/b.js(4,13): error TS2352: Type 'number' cannot be converted to type 'string'.
tests/cases/conformance/jsdoc/b.js(45,16): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'.
Property 'p' is missing in type 'SomeOther'.
tests/cases/conformance/jsdoc/b.js(49,19): error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'.
Property 'x' is missing in type 'SomeOther'.
tests/cases/conformance/jsdoc/b.js(51,17): error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'.
Property 'q' is missing in type 'SomeDerived'.
tests/cases/conformance/jsdoc/b.js(52,17): error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'.
Property 'q' is missing in type 'SomeBase'.
tests/cases/conformance/jsdoc/b.js(58,1): error TS2322: Type '{ p: string | number | undefined; }' is not assignable to type 'SomeBase'.
Types of property 'p' are incompatible.
Type 'string | number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
tests/cases/conformance/jsdoc/b.js(66,8): error TS2352: Type 'boolean' cannot be converted to type 'string | number'.
tests/cases/conformance/jsdoc/b.js(66,15): error TS2304: Cannot find name 'numOrStr'.
tests/cases/conformance/jsdoc/b.js(66,24): error TS1005: '}' expected.
tests/cases/conformance/jsdoc/b.js(66,38): error TS2454: Variable 'numOrStr' is used before being assigned.
tests/cases/conformance/jsdoc/b.js(67,2): error TS2322: Type 'string | number' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/jsdoc/b.js(67,8): error TS2454: Variable 'numOrStr' is used before being assigned.
==== tests/cases/conformance/jsdoc/a.ts (0 errors) ====
var W: string;
==== tests/cases/conformance/jsdoc/b.js (12 errors) ====
// @ts-check
var W = /** @type {string} */(/** @type {*} */ (4));
var W = /** @type {string} */(4); // Error
~~~~~~~~~~~~~~
!!! error TS2352: Type 'number' cannot be converted to type 'string'.
/** @type {*} */
var a;
/** @type {string} */
var s;
var a = /** @type {*} */("" + 4);
var s = "" + /** @type {*} */(4);
class SomeBase {
constructor() {
this.p = 42;
}
}
class SomeDerived extends SomeBase {
constructor() {
super();
this.x = 42;
}
}
class SomeOther {
constructor() {
this.q = 42;
}
}
function SomeFakeClass() {
/** @type {string|number} */
this.p = "bar";
}
// Type assertion should check for assignability in either direction
var someBase = new SomeBase();
var someDerived = new SomeDerived();
var someOther = new SomeOther();
var someFakeClass = new SomeFakeClass();
someBase = /** @type {SomeBase} */(someDerived);
someBase = /** @type {SomeBase} */(someBase);
someBase = /** @type {SomeBase} */(someOther); // Error
~~~~~~~~~~~~~~~~
!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeBase'.
!!! error TS2352: Property 'p' is missing in type 'SomeOther'.
someDerived = /** @type {SomeDerived} */(someDerived);
someDerived = /** @type {SomeDerived} */(someBase);
someDerived = /** @type {SomeDerived} */(someOther); // Error
~~~~~~~~~~~~~~~~~~~
!!! error TS2352: Type 'SomeOther' cannot be converted to type 'SomeDerived'.
!!! error TS2352: Property 'x' is missing in type 'SomeOther'.
someOther = /** @type {SomeOther} */(someDerived); // Error
~~~~~~~~~~~~~~~~~
!!! error TS2352: Type 'SomeDerived' cannot be converted to type 'SomeOther'.
!!! error TS2352: Property 'q' is missing in type 'SomeDerived'.
someOther = /** @type {SomeOther} */(someBase); // Error
~~~~~~~~~~~~~~~~~
!!! error TS2352: Type 'SomeBase' cannot be converted to type 'SomeOther'.
!!! error TS2352: Property 'q' is missing in type 'SomeBase'.
someOther = /** @type {SomeOther} */(someOther);
someFakeClass = someBase;
someFakeClass = someDerived;
someBase = someFakeClass; // Error
~~~~~~~~
!!! error TS2322: Type '{ p: string | number | undefined; }' is not assignable to type 'SomeBase'.
!!! error TS2322: Types of property 'p' are incompatible.
!!! error TS2322: Type 'string | number | undefined' is not assignable to type 'number'.
!!! error TS2322: Type 'undefined' is not assignable to type 'number'.
someBase = /** @type {SomeBase} */(someFakeClass);
// Type assertion cannot be a type-predicate type
/** @type {number | string} */
var numOrStr;
/** @type {string} */
var str;
if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
~~~~~~~~~~~~~~~
!!! error TS2352: Type 'boolean' cannot be converted to type 'string | number'.
~~~~~~~~
!!! error TS2304: Cannot find name 'numOrStr'.
~~
!!! error TS1005: '}' expected.
~~~~~~~~
!!! error TS2454: Variable 'numOrStr' is used before being assigned.
str = numOrStr; // Error, no narrowing occurred
~~~
!!! error TS2322: Type 'string | number' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~~~~~~~~
!!! error TS2454: Variable 'numOrStr' is used before being assigned.
}

View File

@@ -0,0 +1,151 @@
//// [tests/cases/conformance/jsdoc/jsdocTypeTagCast.ts] ////
//// [a.ts]
var W: string;
//// [b.js]
// @ts-check
var W = /** @type {string} */(/** @type {*} */ (4));
var W = /** @type {string} */(4); // Error
/** @type {*} */
var a;
/** @type {string} */
var s;
var a = /** @type {*} */("" + 4);
var s = "" + /** @type {*} */(4);
class SomeBase {
constructor() {
this.p = 42;
}
}
class SomeDerived extends SomeBase {
constructor() {
super();
this.x = 42;
}
}
class SomeOther {
constructor() {
this.q = 42;
}
}
function SomeFakeClass() {
/** @type {string|number} */
this.p = "bar";
}
// Type assertion should check for assignability in either direction
var someBase = new SomeBase();
var someDerived = new SomeDerived();
var someOther = new SomeOther();
var someFakeClass = new SomeFakeClass();
someBase = /** @type {SomeBase} */(someDerived);
someBase = /** @type {SomeBase} */(someBase);
someBase = /** @type {SomeBase} */(someOther); // Error
someDerived = /** @type {SomeDerived} */(someDerived);
someDerived = /** @type {SomeDerived} */(someBase);
someDerived = /** @type {SomeDerived} */(someOther); // Error
someOther = /** @type {SomeOther} */(someDerived); // Error
someOther = /** @type {SomeOther} */(someBase); // Error
someOther = /** @type {SomeOther} */(someOther);
someFakeClass = someBase;
someFakeClass = someDerived;
someBase = someFakeClass; // Error
someBase = /** @type {SomeBase} */(someFakeClass);
// Type assertion cannot be a type-predicate type
/** @type {number | string} */
var numOrStr;
/** @type {string} */
var str;
if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
str = numOrStr; // Error, no narrowing occurred
}
//// [a.js]
var W;
//// [b.js]
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
// @ts-check
var W = ((4));
var W = (4); // Error
/** @type {*} */
var a;
/** @type {string} */
var s;
var a = ("" + 4);
var s = "" + (4);
var SomeBase = (function () {
function SomeBase() {
this.p = 42;
}
return SomeBase;
}());
var SomeDerived = (function (_super) {
__extends(SomeDerived, _super);
function SomeDerived() {
var _this = _super.call(this) || this;
_this.x = 42;
return _this;
}
return SomeDerived;
}(SomeBase));
var SomeOther = (function () {
function SomeOther() {
this.q = 42;
}
return SomeOther;
}());
function SomeFakeClass() {
/** @type {string|number} */
this.p = "bar";
}
// Type assertion should check for assignability in either direction
var someBase = new SomeBase();
var someDerived = new SomeDerived();
var someOther = new SomeOther();
var someFakeClass = new SomeFakeClass();
someBase = (someDerived);
someBase = (someBase);
someBase = (someOther); // Error
someDerived = (someDerived);
someDerived = (someBase);
someDerived = (someOther); // Error
someOther = (someDerived); // Error
someOther = (someBase); // Error
someOther = (someOther);
someFakeClass = someBase;
someFakeClass = someDerived;
someBase = someFakeClass; // Error
someBase = (someFakeClass);
// Type assertion cannot be a type-predicate type
/** @type {number | string} */
var numOrStr;
/** @type {string} */
var str;
if ((numOrStr === undefined)) {
str = numOrStr; // Error, no narrowing occurred
}

View File

@@ -0,0 +1,78 @@
// @allowJS: true
// @suppressOutputPathCheck: true
// @strictNullChecks: true
// @filename: a.ts
var W: string;
// @filename: b.js
// @ts-check
var W = /** @type {string} */(/** @type {*} */ (4));
var W = /** @type {string} */(4); // Error
/** @type {*} */
var a;
/** @type {string} */
var s;
var a = /** @type {*} */("" + 4);
var s = "" + /** @type {*} */(4);
class SomeBase {
constructor() {
this.p = 42;
}
}
class SomeDerived extends SomeBase {
constructor() {
super();
this.x = 42;
}
}
class SomeOther {
constructor() {
this.q = 42;
}
}
function SomeFakeClass() {
/** @type {string|number} */
this.p = "bar";
}
// Type assertion should check for assignability in either direction
var someBase = new SomeBase();
var someDerived = new SomeDerived();
var someOther = new SomeOther();
var someFakeClass = new SomeFakeClass();
someBase = /** @type {SomeBase} */(someDerived);
someBase = /** @type {SomeBase} */(someBase);
someBase = /** @type {SomeBase} */(someOther); // Error
someDerived = /** @type {SomeDerived} */(someDerived);
someDerived = /** @type {SomeDerived} */(someBase);
someDerived = /** @type {SomeDerived} */(someOther); // Error
someOther = /** @type {SomeOther} */(someDerived); // Error
someOther = /** @type {SomeOther} */(someBase); // Error
someOther = /** @type {SomeOther} */(someOther);
someFakeClass = someBase;
someFakeClass = someDerived;
someBase = someFakeClass; // Error
someBase = /** @type {SomeBase} */(someFakeClass);
// Type assertion cannot be a type-predicate type
/** @type {number | string} */
var numOrStr;
/** @type {string} */
var str;
if(/** @type {numOrStr is string} */(numOrStr === undefined)) { // Error
str = numOrStr; // Error, no narrowing occurred
}