Bind assignments to 'this' within static blocks in JS files (#46472)

* Add failing test case.

* Handle 'this' assignments on class static blocks in JavaScript.

* Accepted baselines.
This commit is contained in:
Daniel Rosenwasser 2021-10-22 15:44:35 -07:00 committed by GitHub
parent de1ac8191e
commit 334b8eaa57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 234 additions and 0 deletions

View file

@ -2947,6 +2947,7 @@ namespace ts {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ClassStaticBlockDeclaration:
// this.foo assignment in a JavaScript class
// Bind this property to the containing class
const containingClass = thisContainer.parent;

View file

@ -0,0 +1,30 @@
/src/a.js(10,7): error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: any): arg is any[]; readonly prototype: any[]; }'.
Types of property 'isArray' are incompatible.
Type '(arg: any) => boolean' is not assignable to type '(arg: any) => arg is any[]'.
Signature '(arg: any): boolean' must be a type predicate.
==== /src/a.js (1 errors) ====
class Thing {
static {
this.doSomething = () => {};
}
}
Thing.doSomething();
// GH#46468
class ElementsArray extends Array {
~~~~~~~~~~~~~
!!! error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: any): arg is any[]; readonly prototype: any[]; }'.
!!! error TS2417: Types of property 'isArray' are incompatible.
!!! error TS2417: Type '(arg: any) => boolean' is not assignable to type '(arg: any) => arg is any[]'.
!!! error TS2417: Signature '(arg: any): boolean' must be a type predicate.
static {
const superisArray = super.isArray;
const customIsArray = (arg)=> superisArray(arg);
this.isArray = customIsArray;
}
}
ElementsArray.isArray(new ElementsArray());

View file

@ -0,0 +1,73 @@
//// [a.js]
class Thing {
static {
this.doSomething = () => {};
}
}
Thing.doSomething();
// GH#46468
class ElementsArray extends Array {
static {
const superisArray = super.isArray;
const customIsArray = (arg)=> superisArray(arg);
this.isArray = customIsArray;
}
}
ElementsArray.isArray(new ElementsArray());
//// [a.js]
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var _a, _b;
var _this = this;
var Thing = /** @class */ (function () {
function Thing() {
}
return Thing;
}());
_a = Thing;
(function () {
_a.doSomething = function () { };
})();
Thing.doSomething();
// GH#46468
var ElementsArray = /** @class */ (function (_super) {
__extends(ElementsArray, _super);
function ElementsArray() {
return _super !== null && _super.apply(this, arguments) || this;
}
return ElementsArray;
}(Array));
_b = ElementsArray;
(function () {
var superisArray = _super.isArray;
var customIsArray = function (arg) { return superisArray(arg); };
_b.isArray = customIsArray;
})();
ElementsArray.isArray(new ElementsArray());
//// [a.d.ts]
declare class Thing {
}
declare class ElementsArray extends Array<any> {
constructor(arrayLength?: number);
constructor(arrayLength: number);
constructor(...items: any[]);
}

View file

@ -0,0 +1,49 @@
=== /src/a.js ===
class Thing {
>Thing : Symbol(Thing, Decl(a.js, 0, 0))
static {
this.doSomething = () => {};
>this.doSomething : Symbol(Thing.doSomething, Decl(a.js, 1, 12))
>this : Symbol(Thing, Decl(a.js, 0, 0))
>doSomething : Symbol(Thing.doSomething, Decl(a.js, 1, 12))
}
}
Thing.doSomething();
>Thing.doSomething : Symbol(Thing.doSomething, Decl(a.js, 1, 12))
>Thing : Symbol(Thing, Decl(a.js, 0, 0))
>doSomething : Symbol(Thing.doSomething, Decl(a.js, 1, 12))
// GH#46468
class ElementsArray extends Array {
>ElementsArray : Symbol(ElementsArray, Decl(a.js, 6, 20))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
static {
const superisArray = super.isArray;
>superisArray : Symbol(superisArray, Decl(a.js, 11, 13))
>super.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>super : Symbol(ArrayConstructor, Decl(lib.es5.d.ts, --, --))
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
const customIsArray = (arg)=> superisArray(arg);
>customIsArray : Symbol(customIsArray, Decl(a.js, 12, 13))
>arg : Symbol(arg, Decl(a.js, 12, 31))
>superisArray : Symbol(superisArray, Decl(a.js, 11, 13))
>arg : Symbol(arg, Decl(a.js, 12, 31))
this.isArray = customIsArray;
>this.isArray : Symbol(ElementsArray.isArray, Decl(a.js, 12, 56))
>this : Symbol(ElementsArray, Decl(a.js, 6, 20))
>isArray : Symbol(ElementsArray.isArray, Decl(a.js, 12, 56))
>customIsArray : Symbol(customIsArray, Decl(a.js, 12, 13))
}
}
ElementsArray.isArray(new ElementsArray());
>ElementsArray.isArray : Symbol(ElementsArray.isArray, Decl(a.js, 12, 56))
>ElementsArray : Symbol(ElementsArray, Decl(a.js, 6, 20))
>isArray : Symbol(ElementsArray.isArray, Decl(a.js, 12, 56))
>ElementsArray : Symbol(ElementsArray, Decl(a.js, 6, 20))

View file

@ -0,0 +1,57 @@
=== /src/a.js ===
class Thing {
>Thing : Thing
static {
this.doSomething = () => {};
>this.doSomething = () => {} : () => void
>this.doSomething : () => void
>this : typeof Thing
>doSomething : () => void
>() => {} : () => void
}
}
Thing.doSomething();
>Thing.doSomething() : void
>Thing.doSomething : () => void
>Thing : typeof Thing
>doSomething : () => void
// GH#46468
class ElementsArray extends Array {
>ElementsArray : ElementsArray
>Array : any[]
static {
const superisArray = super.isArray;
>superisArray : (arg: any) => arg is any[]
>super.isArray : (arg: any) => arg is any[]
>super : ArrayConstructor
>isArray : (arg: any) => arg is any[]
const customIsArray = (arg)=> superisArray(arg);
>customIsArray : (arg: any) => boolean
>(arg)=> superisArray(arg) : (arg: any) => boolean
>arg : any
>superisArray(arg) : boolean
>superisArray : (arg: any) => arg is any[]
>arg : any
this.isArray = customIsArray;
>this.isArray = customIsArray : (arg: any) => boolean
>this.isArray : (arg: any) => boolean
>this : typeof ElementsArray
>isArray : (arg: any) => boolean
>customIsArray : (arg: any) => boolean
}
}
ElementsArray.isArray(new ElementsArray());
>ElementsArray.isArray(new ElementsArray()) : boolean
>ElementsArray.isArray : (arg: any) => boolean
>ElementsArray : typeof ElementsArray
>isArray : (arg: any) => boolean
>new ElementsArray() : ElementsArray
>ElementsArray : typeof ElementsArray

View file

@ -0,0 +1,24 @@
// @allowJs: true
// @checkJs: true
// @declaration: true
// @outDir: /out/
// @filename: /src/a.js
class Thing {
static {
this.doSomething = () => {};
}
}
Thing.doSomething();
// GH#46468
class ElementsArray extends Array {
static {
const superisArray = super.isArray;
const customIsArray = (arg)=> superisArray(arg);
this.isArray = customIsArray;
}
}
ElementsArray.isArray(new ElementsArray());