microsoft / microsoft/TypeScript
Misleading error for a generic parameter with a default involving `this`
Personne n'a encore pris cette issue.
- Langage dominant
- Go
- Étoiles
- 111k
- Forks
- 14.3k
- Merge moyen
- 2 j 4 h
- PR mergées (30 j)
- 132
Description
### 🔎 Search Terms
generic type parameter default, assignability, this
### 🕗 Version & Regression Information
- This changed in a9ad94ab3c35615b344c51e721f77655c225b524
### ⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.8.3#code/KYDwDg9gTgLgBAbwL4G4BQaAmwDGAbAQymDnwIGdy4ARCHAVwFtgA7GAHloebYDkDmAPkRo4cFgOAAuGnSasY-ZujHkAliwDmeYDAgtyMmAAs15dEgwaYwKADMCOEgEEWATy7y2I1Ru279QzgTMwsMbDJiUkJKOABRRgAjYExsTABhCDwdHBg1fWpgPBgCADE1Isx2UXidHhhyyoAVNzBgABoagHkAawBGOFAbFkwqT3r2AndhAF5a4HrGvEwWtsGQYdG4Kbc4AH5ZbgV2OLqFJZXW4GEZFmAAN1tOsV6AJnXNqlcPOXq4OfGx1OC3OFWWq2uzzgACEoBAeqwPqwtt9Ad45sDFmDLmshsiqDt9ocvBxMaDmlcbuIHrYagB6OlwCFwADkZLYF2ZeJGBPcRLRpLOHOxEKpd0eUBZcEwEGAVBYEHg5AIeXIdl2JhIOECMCgBGsrNRvwULIAdPTGcyWQKTkKGiLKVKzOJFdtKGpNBJEjpghBgldDe4BWaLWIxBCqBA7HAwHC2rBdiz1FodHoDFKiCQNNrGGAVWpvcBzWIGWGw1abez7RS2oInfLXRR1J6CIXff61my7ZyA9ytoSDpXuw7a3BbjTJebhMggA
### 💻 Code
Here's what essentially was trying to be written in an understandable way:
```ts
type Validator = (data: unknown) => ValidationResult;
interface Cloneable {
data: unknown;
clone(): this;
}
class ValidationResult implements Cloneable {
constructor(public data: T) {
this.isValid = true; // Actual validation logic left off.
}
clone(): this {
return structuredClone(this);
}
isValid: boolean;
}
class Collection> {
// Type 'ReturnType' does not satisfy the constraint 'Cloneable'.
// Type 'ValidationResult' is not assignable to type 'Cloneable'.
// The types returned by 'clone()' are incompatible between these types.
// Type 'ValidationResult' is not assignable to type 'ReturnType'.
constructor(validator: V, items: unknown[]) { } // Actual validation logic left off.
items: C[] = [];
}
```
Here's the a more distilled way of testing interesting cases:
```ts
export {};
declare class Document {
name: DocumentName;
singletons: this;
}
interface AnyDocument {
singletons: this;
}
declare class EmbeddedCollectionDeltaField<
ElementFieldType,
Ok1 extends Document = ElementFieldType extends any ? Document : never,
Ok2 extends AnyDocument = Document,
Broken extends AnyDocument = ElementFieldType extends any ? Document : never
// Type 'ElementFieldType extends any ? Document : never' does not satisfy the constraint 'AnyDocument'.
// Type 'Document' is not assignable to type 'AnyDocument'.
// Types of property 'singletons' are incompatible.
// Type 'Document' is not assignable to type 'ElementFieldType extends any ? Document : never'.
> {}
```
Finally this [playground](https://www.typescriptlang.org/play/#code/KYDwDg9gTgLgBAbwL4G4BQaCWA7GwoBmAhgMbBwDCE2BmA5gK5TAAmAIhCQwLbC4CS2AM4wi2MojRw4AQRYA3PjCbAAXHA5deuADwAiOYtwq9APnTSKRKCyHrNPJfqs2hZ9EgwwAnmHIAVX3IAXjgDBSUTOAAfMJdbPXQ0FmASABtrcnSiISENTkddB20YADkiXgAaOAAFTNw4ULFvU0lpAH0hCCYydWaLOCEcOjTgGGo7fK0nZuqYAAtMIXMMaWwKtSnCso2BsHqYdTrmXA8MFOzmOGzc2WxvYqU4UDxsWy2SnVm4ZtaEKTgnW6UF6P3uKDgAHpIZQINwSnAFks4N14GIWIj5uQlkIGOQ6BBgHkiAB3IjeNCeZKpDJXG55ACi3AARqwUiwqGlRiQYJhqGxgGlRAAxTCClg6AEM0YlUXiwJ+Z4gV7vBXASoAwSYXlENKYABerCVKryMnujwaoSoNHoKnYBRKghEYjIAG1pcBZWK0iw1QBdNB-KlAA) has the most confusing error.
### 🙁 Actual behavior
Multiple errors.
### 🙂 Expected behavior
No error. Or at least a less misleading error message. Specifically the lines `Type 'ValidationResult' is not assignable to type 'Cloneable'.` and `Type 'Document' is not assignable to type 'AnyDocument'.` are both testably false.
### Additional information about the issue
The reason for this misleading error appears to be this snippet:
```ts
if (constraintType && defaultType) {
checkTypeAssignableTo(defaultType, getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType), node.default, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
```
While the types are displayed as `defaultType` being assignable to `constraintType` it's really checking if `defaultType` is assignable to `getTypeWithThisArgument(instantiateType(constraintType, makeUnaryTypeMapper(typeParameter, defaultType)), defaultType)`.
Specifically `this` is being substituted with the `defaultType` and the misleading errors about that ensues where it suddenly switches from talking about `Document` (a part of `defaultType`) being compared to `AnyDocument` (the `constraintType`) to talking comparing `Document` to the `defaultType` because `this = defaultType`. This is confusing because you don't normally expect to see the `defaultType` being compared to a part of the `defaultType`.
I admittedly don't understand the rationale for this specific substitution very well but I find it a bit surprising `this` is substituted with `defaultType` instead of `constratintType`. Regardless of what fix would be necessary to make this work, I can't deduce a way to cause unsoundness if this generic parameter default would be accepted.
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Commencez par la vérification de contrainte/valeur par défaut autour de checkTypeAssignableTo et de l’appel à getTypeWithThisArgument montré dans l’issue. Reproduisez les cas Playground liés et comparez les diagnostics signalés pour les exemples génériques réduits. C’est terminé lorsque les valeurs par défaut valides ne produisent plus d’erreurs, ou lorsque les diagnostics décrivent précisément l’échec réel d’assignabilité.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- typescript
- Domaine
- compilers
- Type d'issue
- Bug
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 30/100