typescript - แทนที่ประเภทวัตถุอย่างลึกด้วยประเภทวัตถุอื่นหากมีคีย์อยู่
ฉันจะแทนที่คุณสมบัติทั้งหมดของ B ด้วยค่าของ A ได้อย่างไร? และตัดคีย์ทั้งหมดของ A ที่ไม่มีใน B ออก
type A = {
a: {
a: string
b: number
c: boolean
d: {
a: any
b: any
}
}
b: { b: null }
}
type B = {
a: {
a: boolean
b: boolean
d: { a: boolean }
}
}
// Result
type C = {
a: {
a: string
b: number
d: { a: any }
}
}
แก้ไข :
นี่คือตัวอย่างว่าทำไมคำตอบของ @catgirlkelly จึงใช้ไม่ได้ในกรณีของฉัน
type DeepReplace<T, U> = T extends object ? U extends object ?
{ [K in keyof T]: K extends keyof U ? DeepReplace<T[K], U[K]> : T[K] } : U : U
type Override<Source, Target> = Source extends object ? {
[K in keyof Source]: K extends keyof Target ? Override<Source[K], Target[K]> : Source[K];
} : Target;
type QueryObj<T> = T extends object ? {
[Key in keyof T]?: QueryObj<T[Key]>;
} : NonNullable<T> extends object ? never : boolean;
type GRAPH_QL_TYPE = {
id: string,
name: string,
Assets?: {
items: ({
id: string,
name: string,
} )[],
} ,
};
function query<Query extends QueryObj<GRAPH_QL_TYPE>>(query: Query) {
// Doesn't work
return {} as Override<Query, GRAPH_QL_TYPE>
// Works
// return {} as DeepReplace<Query, GRAPH_QL_TYPE>
}
const res = query({
name: true,
id: true,
Assets: {
items: [
{
name: true,
id: true,
}
]
}
})
// res.Assets.items[0].name = true with Override, and it equals string with DeepReplace
const reactState: GRAPH_QL_TYPE = res
คำตอบ #1
การแปลงประเภทวัตถุเชิงลึกประเภทนี้มักจะมีกรณีขอบเขตมากมาย (เช่น คุณสมบัติที่ไม่จำเป็น ลายเซ็นดัชนี และประเภทสหภาพ) ดังนั้นใครก็ตามที่เข้ามาพร้อมกับคำถาม "เหมือนกัน" ควรระมัดระวังในการทดสอบคำตอบอย่างรอบคอบ นี่คือวิธีการหนึ่งที่เป็นไปได้:
type DeepReplace<T, U> =
T extends object ? U extends object ? {
[K in keyof T]: K extends keyof U ? DeepReplace<T[K], U[K]> : T[K]
} : U : U
DeepReplace<T, U> ทำการแทนที่ (ส่วนของ) T ด้วย (ส่วนของ) U อย่างซ้ำซ้อน
ถ้า T หรือ U ไม่ใช่วัตถุ จะคืนค่า U ตามเดิม นี่เป็นการตัดสินใจเฉพาะตัวและเป็นกรณีที่อาจเกิดขึ้นได้: เมื่อหนึ่งใน T หรือ U เป็นวัตถุและอีกตัวไม่ใช่ จะไม่ชัดเจน 100% ว่าพฤติกรรมที่ "ถูกต้อง" คืออะไร
หากไม่เช่นนั้น เราจะทำการแมปผ่านคุณสมบัติของ T เพื่อให้คีย์คุณสมบัติใด ๆ K ที่พบใน U ด้วย จะทำให้คุณสมบัติของ T ถูก DeepReplace ด้วยคุณสมบัติที่สอดคล้องกันจาก U นี่คือ "แกนหลัก" ของ DeepReplace<T, U> และน่าจะพบได้ในการใช้งานส่วนใหญ่
หากมีคีย์คุณสมบัติใดของ T ที่ ไม่ พบใน U คุณสมบัตินั้นจะคงไว้เช่นเดิมและจะไม่ถูกแทนที่ นี่เป็นอีกการตัดสินใจหนึ่งและอาจเป็นกรณีขอบเขตด้วยเช่นกัน
อย่างไรก็ตาม มาลองทดสอบมันกับโค้ดตัวอย่างของคุณกันเถอะ:
type C = DeepReplace<B, A>
/* type C = {
a: {
a: string;
b: number;
d: {
a: any;
};
};
} */
ดังนั้นนี่จึงทำงานได้ตามที่ต้องการ เย้! และดูเหมือนว่ามันยังทำงานกับกรณีการใช้งานอื่นของคุณด้วย:
type Query = {
name: true;
id: true;
Assets: {
items: {
name: true;
id: true;
}[];
};
};
type GraphQLType = {
id: string,
name: string,
Assets?: {
items: ({
id: string,
name: string,
})[],
},
};
type QueryResult = DeepReplace<Query, GraphQLType>
/* type QueryResult = {
name: string;
id: string;
Assets: {
items: {
name: string;
id: string;
}[];
} | undefined;
} */
ดีใจสองเท่า ประเภทที่ต้องการอย่างแม่นยำรอบๆ คุณสมบัติที่เป็นทางเลือกและยูเนียนกับ undefined ไม่ชัดเจนสำหรับฉัน 100% แต่ก็อีกครั้ง มันขึ้นอยู่กับรายละเอียดเฉพาะของกรณีการใช้งาน
ลิงก์ Playground ไปยังโค้ด
