Menu

TypeScript Interview Questions: 25 שאלות ותשובות עם קוד

25 שאלות ראיון על TypeScript עם תשובות קצרות ונכונות וקוד, מסודרות מרמת מתחילים עד מתקדמים: any מול unknown, interface מול type, generics, צמצום טיפוסים, utility types, mapped types ו-conditional types, טיפוסיות מבנית, tsconfig ו-TypeScript 7.

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

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

שאלות למתחילים

1. מה זה TypeScript?

TypeScript היא JavaScript עם טיפוסים סטטיים, שפותחה ב-Microsoft. אתם מוסיפים לערכים הערות טיפוס, הקומפיילר בודק אותן, ואז הוא מסיר את הטיפוסים ומוציא JavaScript רגיל שרץ בכל מקום שבו JavaScript רץ.

בלי ההערה @ts-expect-error, הקריאה השנייה היא שגיאת קומפילציה, כך שהבאג אף פעם לא מגיע לפרודקשן.

2. האם TypeScript בודק טיפוסים בזמן ריצה?

לא. הטיפוסים נמחקים בזמן הקומפילציה; בפלט אין מהם שום זכר. ההרצה למעלה מדפיסה 23 כי שום דבר בזמן ריצה לא יודע ש-a אמור להיות מספר. כדי לבדוק נתונים שמגיעים מחוץ לתוכנית (JSON, קלט של משתמשים, תשובות של API) כותבים בדיקות אמיתיות, כמו type guard או כלי ולידציה של סכמות.

3. מהם הטיפוסים הבסיסיים?

string, number (טיפוס אחד למספרים שלמים ולמספרים עשרוניים; אין int), boolean, bigint, symbol, null ו-undefined, ובנוסף מערכים (number[]), tuples ([string, number]), טיפוסי אובייקט, any, unknown, never ו-void. השתמשו בשמות באותיות קטנות: String ו-Number הם טיפוסי אובייקטי העטיפה.

4. מה ההבדל בין any ל-unknown?

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

5. מה זה הסקת טיפוסים (type inference)?

הקומפיילר מחשב טיפוסים שלא כתבתם: let count = 0 הוא number, const mode = "dark" הוא טיפוס הליטרל "dark", וטיפוס ההחזרה של פונקציה נקבע מפקודות ה-return שלה. הכלל הרגיל הוא לכתוב טיפוסים לפרמטרים של פונקציות ולטיפוסי החזרה ציבוריים, ולתת להסקה לטפל במשתנים מקומיים.

6. מה ההבדל בין interface ל-type?

שניהם מתארים מבנים של אובייקטים, ומחלקה יכולה לעשות implements לכל אחד מהם. אפשר לפתוח מחדש interface ולמזג אותו (declaration merging), והוא יכול לעשות extends ל-interfaces אחרים. type alias יכול לתת שם לכל דבר: unions, tuples, טיפוסים פרימיטיביים, mapped types ו-conditional types.

interface User { name: string }
interface User { age: number }       // merged: User has name and age

type Id = string | number;           // only a type alias can be a union
type Pair = [string, number];        // or a tuple
type Admin = User & { role: "admin" };

מוסכמה נפוצה היא interface למבנים של אובייקטים ו-type לכל השאר. ההשוואה המלאה נמצאת בעמוד interface מול type.

7. מהם טיפוסי union ו-intersection?

union מהצורה A | B הוא ערך שהוא אחד מהטיפוסים; אפשר להשתמש רק באיברים שמשותפים לכולם עד שמצמצמים אותו. intersection מהצורה A & B הוא ערך שהוא שניהם בבת אחת, עם כל האיברים של כל אחד.

type Id = string | number;                 // either
type Timestamped = { createdAt: Date };
type Post = { title: string } & Timestamped; // both: title and createdAt

8. מה ההבדל בין void ל-never?

void הוא טיפוס ההחזרה של פונקציה שמסתיימת כרגיל בלי ערך שימושי. never הוא הטיפוס של משהו שלא יכול לקרות: פונקציה שתמיד זורקת שגיאה או נכנסת ללולאה אינסופית, או union שכל המקרים שלו הוסרו. never ניתן להשמה לכל טיפוס, ושום ערך לא ניתן להשמה ל-never.

function log(msg: string): void { console.log(msg); }
function fail(msg: string): never { throw new Error(msg); }
type Impossible = string & number; // never

שאלות ברמה בינונית

9. מה זה צמצום טיפוסים (narrowing)?

צמצום הוא הקומפיילר שעוקב אחרי הבדיקות שלכם ומחדד טיפוס בתוך כל ענף. הוא מבין typeof, instanceof, in, בדיקות שוויון, truthiness ו-type guards שהגדרתם בעצמכם.

10. מה זה type guard שהמשתמש מגדיר?

פונקציה שטיפוס ההחזרה שלה הוא value is T. כשהיא מחזירה true, המשתנה של מי שקרא לה מצטמצם ל-T. הקומפיילר סומך על הפונקציה, ולכן הגוף שלה חייב באמת לבדוק את הערך.

interface Cat { meow(): void }

function isCat(value: unknown): value is Cat {
    return (
        typeof value === "object" &&
        value !== null &&
        "meow" in value &&
        typeof value.meow === "function"
    );
}

assertion function, function assertCat(v: unknown): asserts v is Cat, מצמצמת על ידי זריקת שגיאה במקום החזרה של false.

11. מה זה generics?

פרמטרי טיפוס שמאפשרים לפונקציה, למחלקה או לטיפוס אחד לעבוד עם הרבה טיפוסים ולשמור על הקשר בין הקלט לפלט. T מוסק מהארגומנטים, ו-extends מגביל את מה שהוא יכול להיות.

pluck(users, "email") הייתה שגיאת קומפילציה, כי "email" אינו keyof של טיפוס המשתמש.

12. מה עושים keyof ו-typeof בתוך טיפוס?

keyof T הוא ה-union של שמות המאפיינים של T. במקום של טיפוס, typeof x נותן את הטיפוס של משתנה. ביחד, keyof typeof obj הופך את המפתחות של אובייקט ל-union.

const colors = { red: "#f00", green: "#0f0" };
type Colors = typeof colors;        // { red: string; green: string }
type ColorName = keyof typeof colors; // "red" | "green"

13. מה הם utility types? תנו כמה דוגמאות.

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

Utilityתוצאה
Partial<T>כל מאפיין אופציונלי
Required<T>כל מאפיין חובה
Readonly<T>כל מאפיין readonly
Pick<T, "a" | "b">רק המאפיינים שברשימה
Omit<T, "a">כל מאפיין חוץ מאלה שברשימה
Record<K, V>אובייקט עם מפתחות K וערכים V
Exclude<U, X>, Extract<U, X>הסרה או שמירה של איברי union
NonNullable<T>T בלי null ו-undefined
ReturnType<F>, Parameters<F>טיפוסי ההחזרה או הפרמטרים של פונקציה
Awaited<T>הערך ש-promise נפתר אליו

הרשימה המלאה נמצאת בעמוד על utility types.

14. מה זה discriminated union?

union של טיפוסי אובייקט שחולקים מאפיין "תג" מסוג ליטרל. בדיקה של התג מצמצמת את הערך לאיבר אחד, ובדיקת never בענף ה-default גורמת לקומפיילר לדווח על כל מקרה ששכחתם.

15. מה ההבדל בין as ל-satisfies?

value as T הוא type assertion: הוא אומר לקומפיילר להתייחס לערך כאל T ומדלג על רוב הבדיקות. value satisfies T בודק את הערך מול T אבל שומר על הטיפוס המדויק יותר של הערך עצמו.

type Theme = { primary: string; secondary: string };

const a = { primary: "#07f" } as Theme;        // compiles: the missing key is not reported
const b = { primary: "#07f" } satisfies Theme; // error TS2741: Property 'secondary' is missing
const c = {} as { name: string };              // compiles; c.name is undefined at run time

כשהאובייקט שלם, satisfies גם שומר על הטיפוס המוסק שלו: כשהוא נבדק מול Record<string, string>, המשתנה עדיין יודע בדיוק אילו מפתחות יש לו, ואילו הערת טיפוס הייתה מרחיבה אותו לכל מפתח מחרוזת.

16. מה עושה האופרטור ! אחרי משתנה?

זו ה-non-null assertion: el! מסירה את null ואת undefined מהטיפוס. היא לא מייצרת שום בדיקה, ולכן אם הערך הוא בפועל null, התוכנית קורסת במקום שבו משתמשים בו. העדיפו ?., ?? או if מפורש.

17. מה ההבדל בין private ל-#private?

private נאכף רק על ידי הקומפיילר; בפלט ה-JavaScript המאפיין הוא מאפיין רגיל. #field הוא שדה פרטי של JavaScript, שנאכף על ידי סביבת הריצה.

protected עובד כמו private אבל מאפשר גם גישה מתתי-מחלקות, ו-readonly אוסר השמה מחדש אחרי הבנייה.

18. מה ההבדל בין מחלקה אבסטרקטית ל-interface?

interface הוא רק טיפוס: הוא מתאר מבנה ונעלם מהפלט. מחלקה אבסטרקטית היא מחלקה אמיתית שאי אפשר ליצור ממנה מופע; היא יכולה להחזיק מתודות ממומשות, שדות ובנאים לצד איברים abstract שתתי-מחלקות חייבות לממש. מחלקה יכולה לממש הרבה interfaces אבל להרחיב רק מחלקה אחת.

abstract class Repository<T> {
    protected items: T[] = [];
    abstract validate(item: T): boolean; // subclasses must implement
    add(item: T): void {                 // shared implementation
        if (this.validate(item)) this.items.push(item);
    }
}

19. מה זה function overloading ב-TypeScript?

כמה חתימות קריאה ואחריהן מימוש אחד שהחתימה שלו תואמת לכולן. מי שקורא לפונקציה רואה רק את ה-overloads, ולכן כל קריאה מקבלת טיפוס החזרה מדויק.

function parse(value: string): number;
function parse(value: string[]): number[];
function parse(value: string | string[]): number | number[] {
    return Array.isArray(value) ? value.map(Number) : Number(value);
}

const one = parse("4");          // number
const many = parse(["1", "2"]);  // number[]

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

שאלות למתקדמים

20. מה זו טיפוסיות מבנית (structural typing)?

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

ה-color העודף בסדר כאן כי pixel הוא משתנה. העברה ישירה של ליטרל האובייקט, show({ x: 3, y: 4, color: "red" }), היא שגיאת מאפיין עודף, בדיקה שחלה רק על ליטרלים חדשים. כששני טיפוסים עם אותו מבנה לא אמורים להתערבב (UserId ו-OrderId ששניהם מחרוזות), השתמשו ב-branded type: type UserId = string & { readonly __brand: "UserId" }.

21. איך הייתם מממשים בעצמכם את Readonly ואת Partial?

עם mapped types: עוברים על keyof T ומוסיפים modifier לכל מאפיין.

type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
type MyPartial<T> = { [K in keyof T]?: T[K] };
type Mutable<T> = { -readonly [K in keyof T]: T[K] }; // "-" removes a modifier

type User = { name: string; age: number };
type Draft = MyPartial<User>; // { name?: string; age?: number }

22. מה הם conditional types ו-infer?

T extends U ? X : Y בוחר טיפוס לפי תנאי. בתוך התנאי, infer מצהיר על משתנה טיפוס שתופס חלק מהטיפוס שהתאים. conditional types מתפזרים על פני unions.

type MyReturnType<F> = F extends (...args: any[]) => infer R ? R : never;
type ElementOf<T> = T extends (infer E)[] ? E : T;

type A = MyReturnType<() => Promise<number>>; // Promise<number>
type B = ElementOf<string[]>;                 // string
type C = ElementOf<number | boolean[]>;       // number | boolean (distributed)

עוד תבניות נמצאות בעמוד על conditional types.

23. מה זה קובץ .d.ts, ומה עושה declare?

קובץ הצהרות מחזיק רק טיפוסים לקוד שקיים במקום אחר, כמו ספריית JavaScript או ממשקי API של הדפדפן. declare קובע שערך קיים בלי ליצור אותו: declare const VERSION: string; מתקמפל לכלום. הטיפוסים של ספריות מגיעים יחד עם החבילה או מחבילות @types/{name}, ו-tsc מייצר קובצי .d.ts לקוד שלכם עם declaration: true.

24. מה עושה strict, ואילו אפשרויות של tsconfig הכי חשובות?

"strict": true מפעיל את noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables ו-strictBuiltinIteratorReturn. ב-TypeScript 7 הוא פועל כברירת מחדל. האפשרויות האחרות שמראיינים שואלים עליהן:

אפשרותתשובה בשורה אחת
targetבאיזו גרסה של JavaScript הפלט משתמש
moduleפורמט המודולים של הפלט: nodenext עוקב אחרי הכללים של Node, ו-esnext/preserve שומרים את import בשביל bundler
moduleResolutionאיך imports נמצאים: nodenext דורש ./file.js בקובצי ES module, ו-bundler מקבל ./file
noUncheckedIndexedAccessarr[i] כולל undefined בטיפוס שלו
pathsכינויים ל-imports רק בשביל בודק הטיפוסים; הפלט שומר את הכינוי, ולכן bundler או שדה imports של Node חייבים לפתור אותו
skipLibCheckדילוג על בדיקת קובצי .d.ts, בשביל מהירות
verbatimModuleSyntaximports שמשמשים רק כטיפוסים חייבים להיות מסומנים ב-type; imports אחרים נשמרים כפי שנכתבו

25. מה זה TypeScript 7?

הקומפיילר של TypeScript שנכתב מחדש ב-Go כתוכנה נייטיבית, ושוחרר כגרסה 7 של חבילת ה-npm typescript. הפקודה היא עדיין tsc והשפה זהה, אבל הוא מהיר הרבה יותר מהקומפיילר של 6.x שמבוסס על JavaScript: צוות TypeScript מדווח על האצה של פי 8 עד פי 12 ב-builds מלאים טיפוסיים, בזכות קוד נייטיבי ו-multithreading עם זיכרון משותף. הוא גם אוכף הסרות ש-6.0 סימנה כ-deprecated; למשל baseUrl, outFile, moduleResolution: "node10", module: "amd" ו-alwaysStrict: false הם עכשיו שגיאות (TS5102, TS5108) שאומרות לכם להסיר אותם.

שאלות נפוצות

מהן השאלות הנפוצות ביותר בראיונות על TypeScript?

אלה שעולות הכי הרבה: ההבדל בין any ל-unknown, interface מול type, איך generics עובדים, איך עובדים צמצום טיפוסים ו-type guards, מה utility types כמו Partial, Pick ו-Omit עושים, והאם TypeScript בודק טיפוסים בזמן ריצה (הוא לא).

אילו שאלות TypeScript שואלים מפתחים בכירים?

צפו לכתוב טיפוסים, לא רק לקרוא אותם: לממש Readonly או ReturnType עם mapped types ו-conditional types, להסביר טיפוסיות מבנית ומתי להשתמש ב-branded types, לתכנן discriminated union עם בדיקה ממצה, ולדון בבחירות של tsconfig כמו strict, noUncheckedIndexedAccess ו-module resolution.

איך מתכוננים לראיון על TypeScript?

כתבו תוכניות קטנות כש-strict פועל וקראו את שגיאות הקומפיילר עד שתוכלו לצפות אותן. היו מסוגלים להסביר צמצום טיפוסים, generics עם אילוצים, את ה-utility types העיקריים, ולמה type assertions אינם בטוחים, כל אחד עם דוגמה של שתי שורות.

האם שואלים על TypeScript בראיונות ל-React ול-Angular?

בדרך כלל. Angular עצמה כתובה ב-TypeScript ואפליקציות Angular נכתבות בה, ולכן ראיונות ל-Angular נוטים להניח שאתם מכירים אותה, כולל decorators כמו @Component ו-access modifiers. ראיונות ל-React בבסיס קוד של TypeScript מבקשים לעתים קרובות לתת טיפוסים ל-props, ל-state ול-event handlers, וזה משתמש באותם interfaces, unions ו-generics שמוצגים כאן.

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

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

להתחיל