Recursive Partial<T> ใน TypeScript
ฉันมีอินเทอร์เฟซนี้:
export interface UserSettings
{
one: {
three: number;
four: number;
};
two: {
five: number;
six: number;
};
}
...และต้องการเปลี่ยนมันให้เป็นแบบนี้:
export interface UserSettingsForUpdate
{
one?: {
three?: number;
four?: number;
};
two?: {
five?: number;
six?: number;
};
}
...แต่ Partial<UserSettings> ผลลัพธ์ที่ได้คือ:
{
one?: {
three: number;
four: number;
};
two?: {
five: number;
six: number;
};
}
สามารถใช้ mapped types เพื่อทำให้ทุก property ในทุกระดับเป็น optional ได้หรือไม่ หรือว่าฉันต้องสร้าง interface ด้วยตัวเองสำหรับเรื่องนั้น?
คำตอบ #1
ด้วยการมาถึงของ Conditional Types ในเวอร์ชัน 2.8 ตอนนี้เราสามารถประกาศประเภทย่อยแบบเรียกซ้ำได้ดังนี้
type RecursivePartial<T> = {
[P in keyof T]?:
T[P] extends (infer U)[] ? RecursivePartial<U>[] :
T[P] extends object | undefined ? RecursivePartial<T[P]> :
T[P];
};
แหล่งอ้างอิง:
http://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html
คำตอบ #2
คุณสามารถสร้างประเภทแผนที่ของคุณเองได้แบบนี้:
type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};
โชคร้าย นี่ไม่สามารถใช้ได้กับฟิลด์ที่มีประเภทเป็นอาเรย์ ดูเหมือนว่าจะยังไม่มีวิธีในการทำแมปประเภทตามเงื่อนไขเช่นกัน; เช่น จำกัดเฉพาะประเภทพื้นฐาน ดูที่ https://github.com/Microsoft/TypeScript/pull/12114#issuecomment-259776847 ตอนนี้เป็นไปได้แล้ว ดูคำตอบอื่น ๆ
คำตอบ #3
ฉันได้สร้างห้องสมุดชื่อ tsdef ที่มีรูปแบบ/โค้ดตัวอย่างทั่วไปหลายแบบเช่นนี้
สำหรับกรณีนี้ คุณสามารถใช้มันได้ดังนี้:
import { DeepPartial } from 'tsdef';
let o: DeepPartial<{a: number}> = {};
