Description
π Search Terms
generic type parameter default, assignability, this
π Version & Regression Information
- This changed in a9ad94a
β― Playground Link
π» Code
Here's what essentially was trying to be written in an understandable way:
type Validator = (data: unknown) => ValidationResult<unknown>;
interface Cloneable {
data: unknown;
clone(): this;
}
class ValidationResult<T> implements Cloneable {
constructor(public data: T) {
this.isValid = true; // Actual validation logic left off.
}
clone(): this {
return structuredClone(this);
}
isValid: boolean;
}
class Collection<V extends Validator, C extends Cloneable = ReturnType<V>> {
// Type 'ReturnType<V>' does not satisfy the constraint 'Cloneable'.
// Type 'ValidationResult<unknown>' is not assignable to type 'Cloneable'.
// The types returned by 'clone()' are incompatible between these types.
// Type 'ValidationResult<unknown>' is not assignable to type 'ReturnType<V>'.
constructor(validator: V, items: unknown[]) { } // Actual validation logic left off.
items: C[] = [];
}
Here's the a more distilled way of testing interesting cases:
export {};
declare class Document<DocumentName> {
name: DocumentName;
singletons: this;
}
interface AnyDocument {
singletons: this;
}
declare class EmbeddedCollectionDeltaField<
ElementFieldType,
Ok1 extends Document<any> = ElementFieldType extends any ? Document<ElementFieldType> : never,
Ok2 extends AnyDocument = Document<ElementFieldType>,
Broken extends AnyDocument = ElementFieldType extends any ? Document<ElementFieldType> : never
// Type 'ElementFieldType extends any ? Document<ElementFieldType> : never' does not satisfy the constraint 'AnyDocument'.
// Type 'Document<ElementFieldType>' is not assignable to type 'AnyDocument'.
// Types of property 'singletons' are incompatible.
// Type 'Document<ElementFieldType>' is not assignable to type 'ElementFieldType extends any ? Document<ElementFieldType> : never'.
> {}
Finally this playground 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<unknown>' is not assignable to type 'Cloneable'.
and Type 'Document<ElementFieldType>' 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:
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<ElementFieldType>
(a part of defaultType
) being compared to AnyDocument
(the constraintType
) to talking comparing Document<ElementFieldType>
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.