Skip to content

Commit 53bb4e8

Browse files
authored
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.
1 parent 7a7328a commit 53bb4e8

9 files changed

+83
-3
lines changed

src/compiler/checker.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22321,8 +22321,17 @@ namespace ts {
2232122321
leftType;
2232222322
case SyntaxKind.EqualsToken:
2232322323
const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None;
22324-
checkAssignmentDeclaration(declKind, right);
22324+
checkAssignmentDeclaration(declKind, rightType);
2232522325
if (isAssignmentDeclaration(declKind)) {
22326+
if (!(rightType.flags & TypeFlags.Object) ||
22327+
declKind !== AssignmentDeclarationKind.ModuleExports &&
22328+
declKind !== AssignmentDeclarationKind.Prototype &&
22329+
!isEmptyObjectType(rightType) &&
22330+
!isFunctionObjectType(rightType as ObjectType) &&
22331+
!(getObjectFlags(rightType) & ObjectFlags.Class)) {
22332+
// don't check assignability of module.exports=, C.prototype=, or expando types because they will necessarily be incomplete
22333+
checkAssignmentOperator(rightType);
22334+
}
2232622335
return leftType;
2232722336
}
2232822337
else {
@@ -22339,9 +22348,8 @@ namespace ts {
2233922348
return Debug.fail();
2234022349
}
2234122350

22342-
function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, right: Expression) {
22351+
function checkAssignmentDeclaration(kind: AssignmentDeclarationKind, rightType: Type) {
2234322352
if (kind === AssignmentDeclarationKind.ModuleExports) {
22344-
const rightType = checkExpression(right, checkMode);
2234522353
for (const prop of getPropertiesOfObjectType(rightType)) {
2234622354
const propType = getTypeOfSymbol(prop);
2234722355
if (propType.symbol && propType.symbol.flags & SymbolFlags.Class) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
tests/cases/conformance/jsdoc/bug27327.js(2,1): error TS2322: Type '0' is not assignable to type 'string'.
2+
3+
4+
==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ====
5+
/** @type {string} */
6+
module.exports = 0;
7+
~~~~~~~~~~~~~~
8+
!!! error TS2322: Type '0' is not assignable to type 'string'.
9+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
=== tests/cases/conformance/jsdoc/bug27327.js ===
2+
/** @type {string} */
3+
module.exports = 0;
4+
>module.exports : Symbol("tests/cases/conformance/jsdoc/bug27327", Decl(bug27327.js, 0, 0))
5+
>module : Symbol(export=, Decl(bug27327.js, 0, 0))
6+
>exports : Symbol(export=, Decl(bug27327.js, 0, 0))
7+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/jsdoc/bug27327.js ===
2+
/** @type {string} */
3+
module.exports = 0;
4+
>module.exports = 0 : string
5+
>module.exports : string
6+
>module : { "tests/cases/conformance/jsdoc/bug27327": string; }
7+
>exports : string
8+
>0 : 0
9+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/conformance/jsdoc/bug27327.js(4,1): error TS2322: Type '12' is not assignable to type 'string'.
2+
3+
4+
==== tests/cases/conformance/jsdoc/bug27327.js (1 errors) ====
5+
function C() {
6+
}
7+
/** @type {string} */
8+
C.prototype = 12
9+
~~~~~~~~~~~
10+
!!! error TS2322: Type '12' is not assignable to type 'string'.
11+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/jsdoc/bug27327.js ===
2+
function C() {
3+
>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1))
4+
}
5+
/** @type {string} */
6+
C.prototype = 12
7+
>C.prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1))
8+
>C : Symbol(C, Decl(bug27327.js, 0, 0), Decl(bug27327.js, 1, 1))
9+
>prototype : Symbol(C.prototype, Decl(bug27327.js, 1, 1))
10+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/conformance/jsdoc/bug27327.js ===
2+
function C() {
3+
>C : typeof C
4+
}
5+
/** @type {string} */
6+
C.prototype = 12
7+
>C.prototype = 12 : 12
8+
>C.prototype : string
9+
>C : typeof C
10+
>prototype : string
11+
>12 : 12
12+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// @Filename: bug27327.js
2+
// @noEmit: true
3+
// @allowJs: true
4+
// @checkJs: true
5+
/** @type {string} */
6+
module.exports = 0;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @Filename: bug27327.js
2+
// @noEmit: true
3+
// @allowJs: true
4+
// @checkJs: true
5+
function C() {
6+
}
7+
/** @type {string} */
8+
C.prototype = 12

0 commit comments

Comments
 (0)