Reputation: 5232
function f<T extends {id: string}>(id: T['id']): Partial<T> {
return {id: id}; // ERROR: Type '{ id: T["id"]; }' is not assignable to type 'Partial<T>'
}
I'm trying to figure out why the above code isn't allowed. Is is fundamentally unsound? Or is it because of a limitation of the TypeScript type system?
Upvotes: 2
Views: 920
Reputation: 328362
This is a missing feature; the compiler can't see the assignment as sound and rejects it for the same reason as in Why can't I return a generic 'T' to satisfy a Partial<T>?, even though it would be safe to allow it. There was an issue at microsoft/TypeScript#22229 asking for it to be addressed, but it was closed as "working as intended". From the discussion within it looks like it's just a missing feature or a design limitation.
You could, if you want, use a type assertion:
function fAssert<T extends {id: string}>(id: T['id']): Partial<T> {
return {id: id} as Partial<T>; // assert
}
Or you could build the return value in stages (although this method is too permissive and allows some unsound things which probably won't be fixed anytime soon either):
function fRoundabout<T extends {id: string}>(id: T['id']): Partial<T> {
const ret: Partial<T> = {}; // allowed
ret.id = id; // also works
return ret;
}
I'm not 100% sure why you want the return type to be Partial<T>
, though, since such a type may or may not have values at the keys of T
, whereas your returned object definitely has an id
property and nothing else. It looks more like Pick<T, "id">
than Partial<T>
to me:
function fDifferentReturnType<T extends { id: string }>(id: T['id']): Pick<T, 'id'> {
return { id: id }; // okay
}
Since the example is just a toy example, it's quite possible that your real use case requires Partial<T>
and not {id: T['id']}
. But if not, then you might decide to sidestep the whole Partial
issue entirely.
Okay, hopefully one of those suggestions helps. Good luck!
Upvotes: 1
Reputation: 3061
jcalz suggest 3 options. Which one fits?
I agree with him in the fact that it's not clear from this "toy" example if there's a true need to want the return type Partial<T>
. Pick<T, 'id'>
can be enough. In this case, inference just work fine and it may be a simpler solution:
function f<T extends {id: string}>(id: T['id']) {
return { id }; // type: { id: T['id'] }
}
Upvotes: 1