簡體   English   中英

通用遞歸修改 Typescript 中的給定類型/接口

[英]Generic to recursively modify a given type/interface in Typescript

我正在努力制作一個通用的,它將遞歸地修改在嵌套遞歸數據結構中找到的所有元素。 這是我的數據結構的示例。 使用此遞歸數據定義,任何帖子都可以有無限數量的帶有回復的評論。

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",
}

我想要的是一個通用包裝器,我可以將其與這些以及任何其他數據類型一起使用,這些數據類型將用其他東西替換每個user字段。 我可以為頂層做到這一點:

type UserFilled<T> = Omit<"user", T> & { user: { id: string, name: string }}

但這只會更改 Post 的user字段。 我還希望它向下爬取並替換每個評論的更改user字段,如果有更多字段,則用於反應、喜歡或任何其他包含user的結構。

我已經看到有關遞歸省略某些內容的答案,但我無法使用聯合將修改后的屬性重新添加,我想知道是否有更直接的方法可以做到這一點,而不僅僅是省略而且替換字段?

例如,使用泛型我希望能夠做到這一點:

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",
    }],
};

您可以創建一個 DeepReplace 實用程序來遞歸檢查和替換密鑰。 另外我強烈建議只替換值並確保密鑰保持不變。

// "not object"
type Primitive = string | Function | number | boolean | Symbol | undefined | null 

// If T has key K ("user"), replace it
type ReplaceKey<T, K extends string, R> = T extends Record<K, unknown> ? Omit<T, K> & Record<K, R> : T

// Check and replace object values
type DeepReplaceHelper<T, K extends string, R, ReplacedT = ReplaceKey<T, K, R>> = {
    [Key in keyof ReplacedT]: ReplacedT[Key] extends Primitive ? ReplacedT[Key] : ReplacedT[Key] extends unknown[] ? DeepReplace<ReplacedT[Key][number], K, R>[] : DeepReplace<ReplacedT[Key], K, R>
}

// T = object, K = key to replace, R = replacement value
type DeepReplace<T, K extends string, R> = T extends Primitive ? T : DeepReplaceHelper<T, K, R>

// Define new type for "user" key
interface UserReplacement {
    id: string
    name: string
}


type UserFilled<T> = DeepReplace<T, "user", UserReplacement>

Typescript 操場逐步說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM