Reputation: 36876
Sometimes based on code I know what return value will be and want to specify it using:
getSmth<string>(1)
and not
getSmth(1) as string
but not sure how to do it correctly
Type 'null' is not assignable to type 'T'.
'null' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'string | null'.(2322)
Example
const getName = (id: number) : string | null => null
const getSmth = <T extends string | null = string | null>(id: number | null): T => {
if (!id) {
return null;
}
return getName(id);
};
const x1 = getSmth(1) // should be string | null
const x2 = getSmth<null>(1) // should be null
const x3 = getSmth<string>(1) // should be string
const getSmth2 = <T extends string | null = string | null>(id: number | null): T => {
if (!id) {
return null as T;
}
return getName(id) as T;
};
const y1: string = getSmth2(1) // why getSmth2 asserts to string when return type should bestring | null
Upvotes: 0
Views: 229
Reputation: 20043
Why there is errors if i extend and return correctly?
T
is not guaranteed to be nullable due to the constraint. For example, string
extends string | null
:
// true
type X = string extends string | null ? true : false;
So while the default you give to T
is nullable, the compiler cannot ensure that this is true for all possible T
s. In fact, that's the very thing you're trying do do: passing string
. But once T = string
, returning null
wouldn't be valid anymore.
You can type-assert in your implementation to make it work. This just shuts up the compiler about something that it is indeed correct about, though, but if that is what you want to do:
const getSmth = <T extends string | null = string | null>(id: number | null): T => {
if (!id) {
return null as T;
}
return getName(id) as T;
};
- Question. Why this assertion happening?
Essentially, it's the same issue. The added point here is that the compiler uses the declared type on the left to infer the generic type argument:
// T inferred to be string
const y1: string = getSmth2(1);
// T is inferred to be string | null
const y2: string | null = getSmth2(1);
You're expecting T
to use the default, which happens in this case:
// string | null
const y3 = getSmth2(1);
Upvotes: 2