microsoft / microsoft/TypeScript
Misleading error for a generic parameter with a default involving `this`
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.3k
- 平均マージ
- 2日 4時間
- マージ済み PR(30日)
- 132
説明
### 🔎 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.
コントリビューションガイド
調査の方向性
checkTypeAssignableTo 周辺の制約/default チェックと、issue に示されている getTypeWithThisArgument の呼び出しから始めてください。リンクされている Playground のケースを再現し、簡略化したジェネリックの例で報告される診断を比較してください。完了の条件は、有効な default でエラーが発生しなくなるか、診断が実際の代入可能性の失敗を正確に説明することです。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- typescript
- 領域
- compilers
- issue の種類
- バグ
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 30/100