microsoft / microsoft/TypeScript
Misleading error for a generic parameter with a default involving `this`
- 主要语言
- Go
- 星标
- 111k
- 派生
- 14.3k
- 平均合并
- 2 天 4 小时
- 30 天内合并 PR
- 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 案例,并比较精简 generic 示例所报告的诊断。完成的标准是:有效的 default 不再产生错误,或者诊准确描述实际的可赋值性失败。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- typescript
- 领域
- compilers
- Issue 类型
- 缺陷
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 停滞
- 描述清晰度
- 基本清楚
- 新手友好度
- 30/100