microsoft / microsoft/TypeScript

Object literals should have a `this` type too

Ouverte
#33,201 3 commentaires 1 réaction 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Awaiting More Feedback Experimentation Needed Needs Proposal Suggestion
Langage dominant
Go
Étoiles
111k
Forks
14.3k
Merge moyen
1 j 19 h
PR mergées (30 j)
117

Description

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

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

Commencez par l’exemple TypeScript Playground lié et comparez le type de retour inféré de Clone lorsqu’il est copié de a vers b. Consultez l’issue associée #29122 pour le contexte de ce comportement. Le travail est terminé lorsqu’il est déterminé et implémenté si les méthodes des littéraux d’objet doivent inférer this à partir de l’utilisation de leur objet conteneur, tout en préservant l’accès valide aux membres de l’objet d’origine.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
typescript
Domaine
compilers
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
À l'abandon
Clarté
Plutôt claire
Accessibilité débutants
30/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.