microsoft / microsoft/TypeScript

Object literals should have a `this` type too

Aperta
#33,201 3 commenti 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Awaiting More Feedback Experimentation Needed Needs Proposal Suggestion
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
2g 4h
PR unite (30g)
132

Descrizione

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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia con l’esempio collegato di TypeScript Playground e confronta il tipo restituito inferito di Clone quando viene copiato da a a b. Leggi l’issue correlata #29122 per il contesto su questo comportamento. Il lavoro è completo quando sarà determinato e implementato se i metodi dei letterali oggetto debbano inferire this dall’uso del relativo oggetto contenitore, preservando al contempo l’accesso valido ai membri dell’oggetto originale.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
typescript
Ambito
compilers
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
30/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.