Better checking of assignment declarations (#28387)

Previously, type checking was turned off for all assignment
declarations. This is a problem when the declarations are annotated with
jsdoc types.

This PR checks assignment declarations, *except* for expando
initialisers. Expando initialisers are

1. Empty object types.
2. Function types.
3. Class types.
4. Non-empty object types when the assignment declaration kind is
prototype assignment or module.exports assignment.
This commit is contained in:
Nathan Shively-Sanders 2018-11-15 08:46:11 -08:00 committed by GitHub
parent 7a7328a17f
commit 53bb4e84a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 83 additions and 3 deletions

View File

@ -22321,8 +22321,17 @@ namespace ts {
leftType;
case SyntaxKind.EqualsToken:
const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None;
checkAssignmentDeclaration(declKind, right);
checkAssignmentDeclaration(declKind, rightType);
if (isAssignmentDeclaration(declKind)) {
if (!(rightType.flags & TypeFlags.Object) ||
declKind !== AssignmentDeclarationKind.ModuleExports &&
declKind !== AssignmentDeclarationKind.Prototype &&
!isEmptyObjectType(rightType) &&
!isFunctionObjectType(rightType as ObjectType) &&
!(getObjectFlags(rightType) & ObjectFlags.Class)) {
// don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete
checkAssignmentOperator(rightType);
}
return leftType;
}
else {
@ -22339,9 +22348,8 @@ namespace ts {
return Debug.fail();
}
function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, right: Expression) {
function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) {
if (kind === AssignmentDeclarationKind.ModuleExports) {
const rightType = checkExpression(right, checkMode);
for (const prop of getPropertiesOfObjectType(rightType)) {
const propType = getTypeOfSymbol(prop);
if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) {

View File

@ -0,0 +1,9 @@
tests/cases/conformance/jsdoc/bug27327.js(2,1): error TS2322: Type '0' is not assignable to type 'string'.
==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ====
/** @type {string} */
module.exports = 0;
~~~~~~~~~~~~~~
!!! error TS2322: Type '0' is not assignable to type 'string'.

View File

@ -0,0 +1,7 @@
=== tests/cases/conformance/jsdoc/bug27327.js ===
/** @type {string} */
module.exports = 0;
>module.exports : Symbol("tests/cases/conformance/jsdoc/bug27327", Decl(bug27327.js, 0, 0))
>module : Symbol(export=, Decl(bug27327.js, 0, 0))
>exports : Symbol(export=, Decl(bug27327.js, 0, 0))

View File

@ -0,0 +1,9 @@
=== tests/cases/conformance/jsdoc/bug27327.js ===
/** @type {string} */
module.exports = 0;
>module.exports = 0 : string
>module.exports : string
>module : { "tests/cases/conformance/jsdoc/bug27327": string; }
>exports : string
>0 : 0

View File

@ -0,0 +1,11 @@
tests/cases/conformance/jsdoc/bug27327.js(4,1): error TS2322: Type '12' is not assignable to type 'string'.
==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ====
function C() {
}
/** @type {string} */
C.prototype = 12
~~~~~~~~~~~
!!! error TS2322: Type '12' is not assignable to type 'string'.

View File

@ -0,0 +1,10 @@
=== tests/cases/conformance/jsdoc/bug27327.js ===
function C() {
>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1))
}
/** @type {string} */
C.prototype = 12
>C.prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1))
>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1))
>prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1))

View File

@ -0,0 +1,12 @@
=== tests/cases/conformance/jsdoc/bug27327.js ===
function C() {
>C : typeof C
}
/** @type {string} */
C.prototype = 12
>C.prototype = 12 : 12
>C.prototype : string
>C : typeof C
>prototype : string
>12 : 12

View File

@ -0,0 +1,6 @@
// @Filename: bug27327.js
// @noEmit: true
// @allowJs: true
// @checkJs: true
/** @type {string} */
module.exports = 0;

View File

@ -0,0 +1,8 @@
// @Filename: bug27327.js
// @noEmit: true
// @allowJs: true
// @checkJs: true
function C() {
}
/** @type {string} */
C.prototype = 12