Menu

מערכים ב-TypeScript: טיפוסים, מערך של אובייקטים, map ו-filter

איך נותנים טיפוסים למערכים ב-TypeScript: T[] מול Array<T>, מערכים של אובייקטים, מערכים שמחזיקים כמה טיפוסים, מערכים לקריאה בלבד, ומה map, filter, reduce ו-find מחזירות. ובנוסף, המלכודת של includes עם מערכי ליטרלים.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

טיפוס של מערך ב-TypeScript הוא טיפוס האיבר ואחריו []: string[] הוא מערך של מחרוזות, number[] מערך של מספרים. הכתיב הגנרי Array<string> הוא אותו טיפוס. ברגע שלמערך יש טיפוס, לכל איבר שמוסיפים ולכל איבר שקוראים יש את הטיפוס הזה.

השורה עם @ts-expect-error היא שגיאת קומפילציה (TS2345). כאן היא מסומנת כצפויה כדי שהבלוק עדיין ירוץ, ומכיוון שהטיפוסים נמחקים, ה-42 באמת נדחף למערך בזמן ריצה: הפלט מראה את זה.

string[] מול Array<string>

איך כותביםזהה להערות
string[]Array<string>הכתיב הנפוץ.
(string | number)[]Array<string | number>הסוגריים חובה: string | number[] פירושו "מחרוזת, או מערך של מספרים".
readonly string[]ReadonlyArray<string>בלי push, pop, sort או השמה לפי אינדקס.
User[]Array<User>מערכים של אובייקטים משתמשים בטיפוס של האובייקט.
string[][]Array<Array<string>>מערך דו-ממדי (רשת).

בחרו סגנון אחד לכל בסיס הקוד. ברירת המחדל של הכלל array-type ב-typescript-eslint היא T[].

מערכים של אובייקטים

תארו את האיבר עם type alias או interface, ואז השתמשו ב-Type[]. כל מה שנקרא מהמערך נבדק מול המבנה הזה.

אובייקט ליטרלי שנדחף ל-users חייב להתאים ל-User בדיוק: admin חסר או מאפיין עם שגיאת כתיב הם שגיאת קומפילציה.

map, filter, reduce ו-find עם טיפוסים

מתודות המערך גנריות, ולכן לתוצאות שלהן יש טיפוסים. מה כל מתודה עושה בזמן ריצה מוסבר בעמוד מתודות מערך של JavaScript; הטיפוסים הם מה ש-TypeScript מוסיפה:

מתודהטיפוס התוצאה על T[]
map(fn)U[], כש-U הוא מה ש-fn מחזירה
filter(fn)T[] (או טיפוס צר יותר, ראו בהמשך)
find(fn)T | undefined
findIndex(fn), indexOf(x)number (-1 אם לא נמצא)
some(fn), every(fn), includes(x)boolean
reduce(fn, init)הטיפוס של init (או ארגומנט הטיפוס, reduce<R>(...))
at(i)T | undefined
join(sep)string

הדוגמה האחרונה עובדת כי TypeScript (מאז 5.5) מסיקה ש-(n) => n !== undefined הוא type predicate, ולכן filter מחזירה number[] ולא (number | undefined)[]. לבדיקות שהיא לא מצליחה להסיק, כתבו את ה-predicate בעצמכם: filter((x): x is User => x !== null).

מערכים שמחזיקים יותר מטיפוס אחד

טיפוס איבר מסוג union מאפשר ערבוב. union של טיפוסי מערך לא מאפשר:

כשלכל מיקום יש טיפוס קבוע, כמו זוג [name, age], השתמשו ב-tuple במקום: [string, number] יודע שאינדקס 0 הוא מחרוזת ואינדקס 1 הוא מספר, ו-(string | number)[] לא יודע.

מערכים לקריאה בלבד

readonly T[] מסיר כל מתודה שמשנה את המערך. השתמשו בו לפרמטרים שפונקציה לא אמורה לשנות, ולקבועים.

index.ts(3,12): error TS2339: Property 'push' does not exist on type 'readonly number[]'.

מחקו את השורה של push והבלוק ידפיס 4. תמיד אפשר להעביר number[] שניתן לשינוי למקום שמצפה ל-readonly number[], ולכן פרמטרים לקריאה בלבד לא עולים לקוראים כלום. הבדיקה היא רק בזמן קומפילציה: בזמן ריצה זה מערך רגיל. כדי למיין מערך לקריאה בלבד, מיינו עותק: [...values].sort().

המלכודת של includes עם מערכי ליטרלים

as const הופך מערך ל-tuple לקריאה בלבד של טיפוסי ליטרלים. זה שימושי לרשימה של ערכים מותרים, אבל אז ה-includes שלו מקבל רק את הליטרלים האלה:

עטיפת הבדיקה ב-type guard (value is Color) אומרת שההרחבה קורית פעם אחת, והקוראים מקבלים בחזרה ערך מצומצם.

גישה לפי אינדקס ומערכים ריקים

קריאה של arr[i] נותנת את הטיפוס T, גם כש-i מחוץ לטווח והערך בזמן ריצה הוא undefined. ל-at(i) יש את הטיפוס T | undefined, ואפשרות הקומפיילר noUncheckedIndexedAccess גורמת גם לגישה רגילה לפי אינדקס להחזיר T | undefined.

queue[0].toUpperCase() היה עובר קומפילציה ואז זורק TypeError בזמן ריצה. העדיפו את at(), בדיקת אורך או noUncheckedIndexedAccess כשאינדקס עלול להיות חסר.

שאלות נפוצות

איך מצהירים על טיפוס של מערך ב-TypeScript?

כותבים את טיפוס האיבר ואחריו []: let names: string[] = ["a", "b"]. הצורה הגנרית Array<string> אומרת בדיוק את אותו הדבר. למערך של אובייקטים, השתמשו בטיפוס אובייקט או ב-interface כטיפוס האיבר: User[].

מה ההבדל בין string[] ל-Array<string>?

אין הבדל: אלה שני אופנים לכתוב את אותו טיפוס. string[] נפוץ יותר. הצורה הגנרית קריאה יותר כשטיפוס האיבר מורכב, ובמערכים לקריאה בלבד גם readonly string[] ו-ReadonlyArray<string> זהים.

למה find מחזירה undefined ב-TypeScript?

array.find() מחזירה T | undefined כי ייתכן ששום איבר לא יתאים. תחת strict חייבים לטפל במקרה של undefined, עם בדיקת if, עם optional chaining (found?.name) או עם ערך ברירת מחדל (found ?? fallback), לפני שמשתמשים בתוצאה.

איך נותנים טיפוס למערך עם כמה טיפוסים ב-TypeScript?

השתמשו בטיפוס איבר מסוג union בסוגריים: (string | number)[] הוא מערך שבו כל איבר הוא מחרוזת או מספר. זה שונה מ-string[] | number[], שהוא או מערך של מחרוזות בלבד או מערך של מספרים בלבד. לסדר קבוע של טיפוסים, כמו [string, number], השתמשו ב-tuple.

למה includes נותנת שגיאה על מערך as const?

למערך לקריאה בלבד של ליטרלים, כמו ["red", "green"] as const, יש includes(searchElement: "red" | "green"), ולכן העברה של string רגיל היא השגיאה TS2345. הרחיבו את המערך לצורך הבדיקה, (COLORS as readonly string[]).includes(input), רצוי בתוך type guard שמצמצם את input ל-union של הליטרלים.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל