The issue you are pointing out is indeed similar to the one mentioned in the linked question. The accepted answer from that question states:
Subtyping goes beyond just adding extra properties—it can involve narrowing down the range of acceptable values for those properties.
To illustrate, consider the following interface:
interface RestrictedValues extends UserValues {
avatar: "nonexistent"
}
This interface extends UserValues
, making it compatible with MoreValues
. However, the avatar
property within this interface is limited to only having the value nonexistent
. Therefore, when using the Partial<>
type as the first argument for the set()
function, it should specifically allow the value nonexistent
, not any arbitrary string as implied by UserValues
. For example, consider the code snippet below:
class User<MoreValues extends UserValues = UserValues> extends Table<MoreValues>{
constructor(values: MoreValues) {
super(values);
const thing1: RestrictedValues = { avatar: "nonexistent", id: "", username: "" };
const thing2: MoreValues = thing1;
}
}
In this scenario, thing1
cannot be directly assigned to
thing2</code because there is no guarantee that <code>MoreValues
will always be instantiated with a value such as
{ avatar: "" }
. If
MoreValues
allows other subtypes besides
RestrictedValues
, TypeScript generates the error:
Type 'RestrictedValues' is not assignable to type 'MoreValues'.
'RestrictedValues' meets the constraints of 'MoreValues', but 'MoreValues' may receive a different subtype than 'UserValues'.
A simpler demonstration of this concept involving boolean values is presented in this answer, which provides further clarity on this matter.
The error indicates that your Generic Type P
cannot be
assigned a value of {}
because P
may adhere to a more specific or restricted type that conflicts with the default value.
This means that an empty object {}
may not satisfy all the potential types used by Generic Type P
.
Let's consider a simpler example focusing solely on boolean values for better comprehension:
interface OnlyBoolIdentityInterface<T> {
(arg: T): T;
}
function onlyBoolGeneric<T extends boolean>(arg: T = false): T {
return arg;
}
If we define a type more nuanced than simply a boolean, for instance:
type TrueType = true;
and specialize the function OnlyBoolIdentityInterface
to accept only true values like so:
const onlyTrueIdentity: OnlyBoolIdentityInterface<TrueType> = onlyBoolGeneric;
Even though TrueType
adheres to the constraint enforced by T extends boolean
,
the default value arg: T = false
does not align with TrueType
.
This discrepancy is what the error message aims to convey.
So how can you rectify such errors? Here are some approaches:
- Omit the default value
- Ensure that
T
encompasses the specialized type of the default parameter (in this case, false)
- Directly align
T
with parameters utilizing default values
For additional insights into this error message, refer to the corresponding
issue:
https://github.com/Microsoft/TypeScript/issues/29049.