Typescript, JavaScript: איך ליצור סוג משולב בצורה דינמית באמצעות לולאת typeof?


נניח שיש לנו:

const array = [a, b, c]  // could be any number of items in here
type T = ???  // how to write this?

כך שהתוצאה שווה ל

type T = typeof a & typeof b & typeof c

למעט ש-T נוצר באופן דינמי בהתבסס על לולאה דרך array (מאחר ש-array עשוי למעשה להכיל פריטים אחרים מלבד a, b, c). פתרון המשתמש בממשקים עשוי להיות מקובל גם כן.

תשובה #1

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

let a = { aProp: 1 };
let b = { bProp: 1 };
let c = { cProp: 1 };
const array = [a, b, c]  // typed as ({ aProp: number; } | { bProp: number; } | { cProp: number; })[]

מתחילים מזה, אנחנו יכולים להפוך את האיחוד לחיתוך באמצעות סוגים מותנים (ראה תשובה זו להסבר על UnionToIntersection) ולהשתמש בשאילתת סוג כדי לקבל את סוגו של פריט במערך:

type UnionToIntersection<U> = 
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type T = UnionToIntersection<typeof array[number]>  // { aProp: number; } & { bProp: number; } & { cProp: number; }

תשובה #2

סוגי Typescript קיימים רק בזמן הקומפילציה, הם יוסרו בזמן הריצה (מה שהופך את זה ל-JavaScript). מכיוון שהערכים של המערך קיימים רק בזמן הריצה, אין דרך לקבל את הסוג שלהם בזמן הקומפילציה.