I am trying to format date strings into date objects recursively, but I'm getting an error:
type JsonBody<T> = T extends Date
? string
: T extends (infer U)[]
? JsonBody<U>[]
: T extends object
? { [P in keyof T]: JsonBody<T[P]> }
: T;
type Person = {
name: string;
friend?: Person;
createdAt: Date;
};
type PersonWithFriend = Omit<Person, "friend"> & Required<Pick<Person, "friend">>;
function formatPerson<T extends Person>(body: JsonBody<T>): T {
return {
...body,
friend: body.friend && formatPerson(body.friend),
createdAt: new Date(body.createdAt)
};
// Type 'JsonBody<T> & { friend: Person | undefined; createdAt: Date; }' is not assignable to type 'T'.
// 'JsonBody<T> & { friend: Person | undefined; createdAt: Date; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Person'.
}
const one: JsonBody<Person> = { name: 'One', createdAt: '2021-01-21 00:59:11.07+00' };
const two: JsonBody<PersonWithFriend> = { name: 'One', friend: { name: 'Two', createdAt: '2021-01-21 00:59:11.07+00' }, createdAt: '2021-01-21 00:59:11.07+00' };
const oneFormatted = formatPerson(one).createdAt; // should be Date
const twoFormatted = formatPerson(two).friend.createdAt; // should be Date
See in Playground
Why does formatPerson(JsonBody<T extend Person>)
not return T
and why does T
not become Person
or PersonWithFriend
depending on the passed argument?
Thank you for the help in advance.