microsoft / microsoft/TypeScript

Object literals should have a `this` type too

Offen
#33,201 3 Kommentare 1 Reaktion 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Awaiting More Feedback Experimentation Needed Needs Proposal Suggestion
Vorherrschende Sprache
Go
Sterne
111k
Forks
14.3k
Ø Merge
2 T. 4 Std.
Gemergte PRs (30 T.)
132

Beschreibung

TypeScript Version: 3.7.0-dev.20190831

Search Terms: this return type object composing composition

Code

I tried writing some self-contained parts of objects as a kind of multiple-inheritance or object composition, which I would combine later, and ran into this case.

const a = {
	Clone() {
		return this;
	},
	x: 1,
};

const b = {
	Clone: a.Clone,
	y: 2,
};

console.log(b.Clone().x); // number, bad! Should be an error!
console.log(b.Clone().y); // compiler error, bad! This should be acceptable!

Expected behavior: this, the return type of Clone, should evaluate to typeof b in b.Clone()

Actual behavior: It evaluates to typeof a, since it was defined in a

This can be circumvented by defining this as a type parameter like so:

const a = {
	Clone<T>(this: T) {
		return this;
	},
	x: 1,
}

const b = {
	Clone: a.Clone,
	y: 2
};

console.log(b.Clone().x); // compiler error, good!
console.log(b.Clone().y); // works! Also good!

Another interesting problem at play here though, is that using a type parameter for this also means that TS doesn't know what could be inside of this. This means you have to manually specify whatever members you hope to have access to. It would be nice if you could do T extends typeof a and it would automatically drop all the members of a in there. Right now, it will error if you do this:

'a' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts(7022)

I think all methods like this should, therefore, be implicitly equivalent to the following:

const a = {
	Clone<T extends typeof a>(this: T) {
		console.log(this.x); // should work
		return this;
	},
	x: 1,
}

Then, b.Clone() would error since b is not a superset of a. Unless you did c = Object.assign({}, a, b), and did c.Clone()

Playground Link: https://www.typescriptlang.org/play/?target=6#code/MYewdgzgLgBAhjAvDA3gKAJAGEA24CmAFAJSqYYBO+UArhWDFABYCWEA3JgL4A0mAHgC4YARjRdOaUJFgAjJGWx4w+YXAB0uAnwwBPYQCZxk6RBA586vAHNCszcqLF1-YuxgB6DzBpgAJvgAZiwqflLgZhZWILb2Wiok6rpunt6gALYADiwWFDD4FBQgFEA

Related Issues: https://github.com/microsoft/TypeScript/issues/29122

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginnen Sie mit dem verlinkten TypeScript Playground-Beispiel und vergleichen Sie den inferierten Rückgabetyp von Clone, wenn es von a nach b kopiert wird. Lesen Sie zur Einordnung dieses Verhaltens das zugehörige Issue #29122. Als abgeschlossen gilt die Ermittlung und Implementierung, ob Methoden in Objektliteralen this aus der Verwendung ihres enthaltenden Objekts inferieren sollten, wobei der gültige Zugriff auf Mitglieder des ursprünglichen Objekts erhalten bleibt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
typescript
Bereich
compilers
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
30/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.