reactjs - איך להסיק סוגים של אובייקט שנוצר ממבנה נתונים?


אני מנסה ליישם משהו דומה לתכונת "Controls" של Storybook שבה אתה יכול להגדיר מספר תכונות, והן הופכות לבקרים בממשק המשתמש.

הגדרתי סוג סכימה וסכימה של איך ליצור את הבקרים האלה:

// Example schema
var newSchema: BlockSchema = {
  title: "New Schema",
  controls: {
    name: {
      type: 'string',
      placeholder: 'Please insert your name'
    },
    size: {
      type: 'select',
      options: ['quarter', 'half', 'full']
    },
    hasInfo: {
      type: 'bool'
    },
    amount: {
      type: 'number'
    }
  }
}

אבל עכשיו אני צריך סוג שהוא התוצאה של מה שהמשתמש בחר. סוג לערכים הסופיים, משהו כמו:

type MapControlTypes = {
  bool: boolean;
  string: string;
  select: string;
  number: number;
};

type InferType<T extends BlockSchema> = { /* MapControlTypes<?????????> */ }

type NewSchemaControls = InferType<typeof newSchema>;

/* Expected result:
  NewSchemaControls = {
    name: string;
    size: string;
    hasInfo: boolean;
    amount: number;
  }
*/

אני צריך להסיק את הסוגים מהתכונה controls של הסכמה שלי, אבל איך אוכל ליישם את ההסקה הזו? הנה חדר משחקים עם קוד דוגמה מלא


ניסיתי ליישם את זה, ואת הפתרון הזה. אבל הם לא עובדים טוב וגם תומכים רק בשני סוגים.

הפתרון של Titian Cernicova-Dragomir גם לא עבד. מגרש משחקים, אבל יש לו בעיה מאוד דומה שקרתה כשניסיתי פתרונות אחרים. אולי זה בגלל שאינני משתמש ב-MapControlTypes על ה-ControlSchema שלי?


נפתר!

תשובה #1

אתה יכול לעשות זאת, באמצעות סוג ממופה, אבל קודם עליך לשמור על הסוג המקורי של הסכמה. אם תוסיף לו הערת סוג, המידע על שדות מסוימים וסוגים יאבד. זה יהיה פשוט BlockSchema

הדרך הקלה ביותר לעשות זאת היא להשמיט את ההערה, ולהשתמש בהצהרת as const כדי לגרום למקמפל להסיק סוגים מילוליים עבור type.

עם המידע הנוסף הזה ביד, אנו יכולים אז להשתמש בסוג ממופה כדי להמיר את הסכמה לסוג אובייקט:

type InferType<T extends BlockSchema> = {
  -readonly [P in keyof T['controls']]: MapControlTypes[T['controls'][P]['type']]
}

קישור למגרש משחקים

אתה יכול גם להשתמש בפונקציה כדי ליצור את הסכמה, ולהיות סלקטיבי יותר לגבי מה מקבל את הטיפול רק לקריאה:

function buildBlockSchema<B extends BlockSchema>(b: B) {
  return b
}

קישור למגרש משחקים