TypeScript/tests/baselines/reference/classCanExtendConstructorFunction.symbols
Nathan Shively-Sanders 53a756ea63
Type this in more constructor functions (#39447)
* Type `this` in more constructor functions

Previously,  `this: this` in constructor functions only when there was
an explicit `@constructor` tag on the function. Now, `this: this` for
any function that's known to be a constructor function.

This improves completions inside constructor functions; also note that
previously the compiler *did* type `this: this` inside methods of constructor
functions, so this fix makes us more consistent. This is reflected in
the large number of baselines that improve.

The fix is a simple switch to `isJSConstructor`, which is the standard
way to detect constructor functions. I'm not sure why the original PR
didn't use this method.

I remember discussing this limitation in the original bug, #25979, and
I guess I decided that it made sense. But I was heavily primed by the bug's
framing of the problem in terms of `noImplicitThis`, which *should*
require an explicit `@constructor` tag.

With better typing comes better detection of `@readonly` assignment; I
had to fix the readonly detection code to use `isJSConstructor` as well.

* Remove `Add @class tag` fix for noImplicitThis.

The new rules mean that it never applies. It's possible that it should
apply to functions like

```js
function f() {
  this.init()
}
```

In which `init` is never defined, but I think this program is incomplete
enough that not offering the fix is fine.

* Fix precedence of `@this`

Previously, both `@class` and `@this` in a jsdoc would cause the `@this`
annotation to be ignored. This became a worse problem with this PR,
because `this` is correctly typed even without the annotation.

This commit makes sure that `@this` is checked first and used if
present.
2020-07-08 08:44:17 -07:00

246 lines
9.1 KiB
Plaintext

=== tests/cases/conformance/salsa/first.js ===
/**
* @constructor
* @param {number} numberOxen
*/
function Wagon(numberOxen) {
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>numberOxen : Symbol(numberOxen, Decl(first.js, 4, 15))
this.numberOxen = numberOxen
>this.numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>this : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>numberOxen : Symbol(numberOxen, Decl(first.js, 4, 15))
}
/** @param {Wagon[]=} wagons */
Wagon.circle = function (wagons) {
>Wagon.circle : Symbol(Wagon.circle, Decl(first.js, 6, 1))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>circle : Symbol(Wagon.circle, Decl(first.js, 6, 1))
>wagons : Symbol(wagons, Decl(first.js, 8, 25))
return wagons ? wagons.length : 3.14;
>wagons : Symbol(wagons, Decl(first.js, 8, 25))
>wagons.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>wagons : Symbol(wagons, Decl(first.js, 8, 25))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
}
/** @param {*[]=} supplies - *[]= is my favourite type */
Wagon.prototype.load = function (supplies) {
>Wagon.prototype : Symbol(Wagon.load, Decl(first.js, 10, 1))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>load : Symbol(Wagon.load, Decl(first.js, 10, 1))
>supplies : Symbol(supplies, Decl(first.js, 12, 33))
}
/** @param {*[]=} supplies - Yep, still a great type */
Wagon.prototype.weight = supplies => supplies ? supplies.length : -1
>Wagon.prototype : Symbol(Wagon.weight, Decl(first.js, 13, 1))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>weight : Symbol(Wagon.weight, Decl(first.js, 13, 1))
>supplies : Symbol(supplies, Decl(first.js, 15, 24))
>supplies : Symbol(supplies, Decl(first.js, 15, 24))
>supplies.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>supplies : Symbol(supplies, Decl(first.js, 15, 24))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
Wagon.prototype.speed = function () {
>Wagon.prototype : Symbol(Wagon.speed, Decl(first.js, 15, 68))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>prototype : Symbol(Function.prototype, Decl(lib.es5.d.ts, --, --))
>speed : Symbol(Wagon.speed, Decl(first.js, 15, 68))
return this.numberOxen / this.weight()
>this.numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>this : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>this.weight : Symbol(Wagon.weight, Decl(first.js, 13, 1))
>this : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>weight : Symbol(Wagon.weight, Decl(first.js, 13, 1))
}
// ok
class Sql extends Wagon {
>Sql : Symbol(Sql, Decl(first.js, 18, 1))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
constructor() {
super(); // error: not enough arguments
>super : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
this.foonly = 12
>this.foonly : Symbol(Sql.foonly, Decl(first.js, 22, 16))
>this : Symbol(Sql, Decl(first.js, 18, 1))
>foonly : Symbol(Sql.foonly, Decl(first.js, 22, 16))
}
/**
* @param {Array.<string>} files
* @param {"csv" | "json" | "xmlolololol"} format
* This is not assignable, so should have a type error
*/
load(files, format) {
>load : Symbol(Sql.load, Decl(first.js, 24, 5))
>files : Symbol(files, Decl(first.js, 30, 9))
>format : Symbol(format, Decl(first.js, 30, 15))
if (format === "xmlolololol") {
>format : Symbol(format, Decl(first.js, 30, 15))
throw new Error("please do not use XML. It was a joke.");
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
else {
super.speed() // run faster
>super.speed : Symbol(Wagon.speed, Decl(first.js, 15, 68))
>super : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>speed : Symbol(Wagon.speed, Decl(first.js, 15, 68))
if (super.weight() < 0) {
>super.weight : Symbol(Wagon.weight, Decl(first.js, 13, 1))
>super : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
>weight : Symbol(Wagon.weight, Decl(first.js, 13, 1))
// ????????????????????????
}
}
}
}
var db = new Sql();
>db : Symbol(db, Decl(first.js, 42, 3), Decl(first.js, 42, 19))
>Sql : Symbol(Sql, Decl(first.js, 18, 1))
db.numberOxen = db.foonly
>db.numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>db : Symbol(db, Decl(first.js, 42, 3), Decl(first.js, 42, 19))
>numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>db.foonly : Symbol(Sql.foonly, Decl(first.js, 22, 16))
>db : Symbol(db, Decl(first.js, 42, 3), Decl(first.js, 42, 19))
>foonly : Symbol(Sql.foonly, Decl(first.js, 22, 16))
// error, can't extend a TS constructor function
class Drakkhen extends Dragon {
>Drakkhen : Symbol(Drakkhen, Decl(first.js, 43, 25))
>Dragon : Symbol(Dragon, Decl(second.ts, 0, 0))
}
=== tests/cases/conformance/salsa/second.ts ===
/**
* @constructor
*/
function Dragon(numberEaten: number) {
>Dragon : Symbol(Dragon, Decl(second.ts, 0, 0))
>numberEaten : Symbol(numberEaten, Decl(second.ts, 3, 16))
this.numberEaten = numberEaten
>numberEaten : Symbol(numberEaten, Decl(second.ts, 3, 16))
}
// error!
class Firedrake extends Dragon {
>Firedrake : Symbol(Firedrake, Decl(second.ts, 5, 1))
>Dragon : Symbol(Dragon, Decl(second.ts, 0, 0))
constructor() {
super();
}
}
// ok
class Conestoga extends Wagon {
>Conestoga : Symbol(Conestoga, Decl(second.ts, 11, 1))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
constructor(public drunkOO: true) {
>drunkOO : Symbol(Conestoga.drunkOO, Decl(second.ts, 14, 16))
// error: wrong type
super('nope');
>super : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
}
// should error since others is not optional
static circle(others: (typeof Wagon)[]) {
>circle : Symbol(Conestoga.circle, Decl(second.ts, 17, 5))
>others : Symbol(others, Decl(second.ts, 19, 18))
>Wagon : Symbol(Wagon, Decl(first.js, 0, 0), Decl(first.js, 6, 1))
return others.length
>others.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
>others : Symbol(others, Decl(second.ts, 19, 18))
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
}
}
var c = new Conestoga(true);
>c : Symbol(c, Decl(second.ts, 23, 3))
>Conestoga : Symbol(Conestoga, Decl(second.ts, 11, 1))
c.drunkOO
>c.drunkOO : Symbol(Conestoga.drunkOO, Decl(second.ts, 14, 16))
>c : Symbol(c, Decl(second.ts, 23, 3))
>drunkOO : Symbol(Conestoga.drunkOO, Decl(second.ts, 14, 16))
c.numberOxen
>c.numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
>c : Symbol(c, Decl(second.ts, 23, 3))
>numberOxen : Symbol(Wagon.numberOxen, Decl(first.js, 4, 28))
=== tests/cases/conformance/salsa/generic.js ===
/**
* @template T
* @param {T} flavour
*/
function Soup(flavour) {
>Soup : Symbol(Soup, Decl(generic.js, 0, 0))
>flavour : Symbol(flavour, Decl(generic.js, 4, 14))
this.flavour = flavour
>this.flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>this : Symbol(Soup, Decl(generic.js, 0, 0))
>flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>flavour : Symbol(flavour, Decl(generic.js, 4, 14))
}
/** @extends {Soup<{ claim: "ignorant" | "malicious" }>} */
class Chowder extends Soup {
>Chowder : Symbol(Chowder, Decl(generic.js, 6, 1))
>Soup : Symbol(Soup, Decl(generic.js, 0, 0))
log() {
>log : Symbol(Chowder.log, Decl(generic.js, 8, 28))
return this.flavour
>this.flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>this : Symbol(Chowder, Decl(generic.js, 6, 1))
>flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
}
}
var soup = new Soup(1);
>soup : Symbol(soup, Decl(generic.js, 14, 3))
>Soup : Symbol(Soup, Decl(generic.js, 0, 0))
soup.flavour
>soup.flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>soup : Symbol(soup, Decl(generic.js, 14, 3))
>flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
var chowder = new Chowder({ claim: "ignorant" });
>chowder : Symbol(chowder, Decl(generic.js, 16, 3))
>Chowder : Symbol(Chowder, Decl(generic.js, 6, 1))
>claim : Symbol(claim, Decl(generic.js, 16, 27))
chowder.flavour.claim
>chowder.flavour.claim : Symbol(claim, Decl(generic.js, 7, 20))
>chowder.flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>chowder : Symbol(chowder, Decl(generic.js, 16, 3))
>flavour : Symbol(Soup.flavour, Decl(generic.js, 4, 24))
>claim : Symbol(claim, Decl(generic.js, 7, 20))
var errorNoArgs = new Chowder();
>errorNoArgs : Symbol(errorNoArgs, Decl(generic.js, 18, 3))
>Chowder : Symbol(Chowder, Decl(generic.js, 6, 1))
var errorArgType = new Chowder(0);
>errorArgType : Symbol(errorArgType, Decl(generic.js, 19, 3))
>Chowder : Symbol(Chowder, Decl(generic.js, 6, 1))