I am struggling to make a generic which would recursively modify all elements found in a structure of nested, recursive data. Here is an example of my data structure. Any post could have an infinite number of comments with replies using this recursive data definition.
type Post = {
user: string,
content: string,
comments: Comment[],
reactions: Reaction[],
}
type Comment = {
user: string,
content: string,
replies: Comment[],
}
type Reaction = {
user: string,
reaction: "laugh" | "cry" | "smile",
}
What I would like is a generic wrapper that I could use with these and any other data types that would replace every user
field with something else. I could do this for the top level:
type UserFilled<T> = Omit<"user", T> & { user: { id: string, name: string }}
But this would only change the user
field for the Post. I would also like it to crawl down and replace the change the user
field for each of the comments, and if there were more fields, for the reactions, likes, or any other structures with a user
in them.
I've seen this answer about omitting something recursively but I was not able to add the modified property back in using a union and I'm wondering if there's a more straightforward way to do this while not just omitting but also replacing the field?
For example, using the generic I would like to be able to do this:
const post: Post = {
user: "1234",
content: "this is a post",
comments: [{
user: "3456",
content: "I agree",
replies: [{
user: "1234",
content: "thanks",
}],
}],
reactions: [{
user: "5678",
reaction: "smile",
}],
};
const postWUserInfo: UserFilled<Post> = {
user: { id: "1234", name: "Bob" },
content: "this is a post",
comments: [{
user: { id: "3456", name: "Jim" },
content: "I agree",
replies: [{
user: { id: "1234", name: "Bob" },
content: "thanks",
}],
}],
reactions: [{
user: { id: "5678", name: "Jim" },
reaction: "smile",
}],
};