5.7 טיפוסי שירות ודפוסים מתקדמים תרגול
תרגול - טיפוסי שירות ודפוסים מתקדמים¶
תרגיל 1 - Partial, Required, Readonly¶
נתון האינטרפייס:
interface Product {
id: number;
name: string;
price: number;
description?: string;
category?: string;
inStock: boolean;
}
א. כתבו פונקציה updateProduct שמקבלת Product ו-Partial<Product> (עדכונים) ומחזירה Product מעודכן.
ב. כתבו פונקציה createProduct שמקבלת Required<Product> (כל השדות חובה, כולל description ו-category) ומחזירה Product.
ג. כתבו פונקציה freezeProduct שמקבלת Product ומחזירה Readonly<Product>. נסו לשנות שדה בתוצאה ובדקו שאתם מקבלים שגיאה.
ד. צרו טיפוס ProductDraft שבו כל השדות הם אופציונליים חוץ מ-name שהוא חובה. רמז: שלבו Pick עם Partial.
תרגיל 2 - Pick ו-Omit¶
נתון:
interface Employee {
id: number;
firstName: string;
lastName: string;
email: string;
department: string;
salary: number;
hireDate: Date;
manager?: Employee;
}
א. צרו טיפוס EmployeeCard עם רק firstName, lastName, department (שימוש ב-Pick).
ב. צרו טיפוס EmployeePublicInfo בלי salary ו-manager (שימוש ב-Omit).
ג. צרו טיפוס NewEmployeeInput בלי id ו-hireDate (הם נוצרים אוטומטית).
ד. כתבו פונקציה toEmployeeCard שמקבלת Employee ומחזירה EmployeeCard.
ה. כתבו פונקציה createEmployee שמקבלת NewEmployeeInput ומחזירה Employee (מייצרת id ו-hireDate אוטומטית).
תרגיל 3 - Record¶
א. הגדירו טיפוס GradeBook כ-Record<string, number[]> (שם תלמיד -> מערך ציונים). כתבו פונקציה getAverage שמקבלת GradeBook ושם תלמיד, ומחזירה את הממוצע שלו (או null אם לא נמצא).
ב. הגדירו type StatusColor = Record<"info" | "success" | "warning" | "error", string>. צרו אובייקט statusColors עם צבע לכל סטטוס. מה קורה אם שוכחים סטטוס אחד?
ג. הגדירו טיפוס TranslationMap כ-Record<string, Record<string, string>> (שפה -> מפתח -> תרגום). צרו אובייקט עם תרגומים לאנגלית ועברית. כתבו פונקציה translate שמקבלת שפה, מפתח, ומחזירה את התרגום (או את המפתח עצמו אם לא נמצא).
תרגיל 4 - ReturnType ו-Parameters¶
א. נתונה הפונקציה:
function createConfig(
theme: "light" | "dark",
language: string,
features: string[],
debug?: boolean
) {
return {
theme,
language,
features,
debug: debug ?? false,
version: "1.0.0",
createdAt: new Date()
};
}
השתמשו ב-ReturnType כדי ליצור טיפוס AppConfig מהפונקציה. השתמשו ב-Parameters כדי ליצור טיפוס ConfigParams.
ב. כתבו פונקציה createDefaultConfig שלא מקבלת פרמטרים ומחזירה AppConfig עם ערכי ברירת מחדל.
ג. כתבו פונקציה wrapWithLogging גנרית שמקבלת פונקציה כלשהי ומחזירה פונקציה חדשה עם אותה חתימה, שמדפיסה ל-console את הארגומנטים לפני הקריאה ואת התוצאה אחריה.
תרגיל 5 - mapped types¶
א. ממשו type Nullable<T> שהופך את כל השדות ל-T[K] | null:
type NullableUser = Nullable<User>;
// { name: string | null; age: number | null; email: string | null }
ב. ממשו type Mutable<T> שמסיר readonly מכל השדות (ההפך של Readonly):
interface FrozenPoint {
readonly x: number;
readonly y: number;
}
type MutablePoint = Mutable<FrozenPoint>;
// { x: number; y: number }
ג. ממשו type Getters<T> שיוצר getter לכל שדה:
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number; getEmail: () => string }
רמז: השתמשו ב-as ו-Capitalize.
תרגיל 6 - conditional types ו-infer¶
א. ממשו type IsArray<T> שמחזיר true אם T הוא מערך, אחרת false:
ב. ממשו type UnwrapPromise<T> שמחלץ את הטיפוס מתוך Promise (רקורסיבי - תומך ב-Promise
type A = UnwrapPromise<Promise<string>>; // string
type B = UnwrapPromise<Promise<Promise<number>>>; // number
type C = UnwrapPromise<string>; // string
ג. ממשו type FunctionInfo<T> שמחזיר אובייקט עם מידע על פונקציה:
type Info = FunctionInfo<(name: string, age: number) => boolean>;
// { params: [name: string, age: number]; returnType: boolean; paramCount: 2 }
רמז: paramCount יכול להשתמש ב-["length"] על הטאפל.
תרגיל 7 - שילוב הכל - מערכת טפסים¶
בנו מערכת טיפוסים לטפסים:
א. הגדירו טיפוס FormField<T> עם:
- value: T
- error: string | null
- touched: boolean
- dirty: boolean
ב. הגדירו mapped type FormFields<T> שממפה כל שדה של T ל-FormField<T[K]>:
interface LoginForm {
username: string;
password: string;
rememberMe: boolean;
}
type LoginFormFields = FormFields<LoginForm>;
// {
// username: FormField<string>;
// password: FormField<string>;
// rememberMe: FormField<boolean>;
// }
ג. הגדירו טיפוס FormErrors<T> כ-Partial<Record<keyof T, string>>.
ד. הגדירו טיפוס FormValues<T> שמחלץ רק את ה-values מ-FormFields<T>:
type LoginValues = FormValues<LoginFormFields>;
// { username: string; password: string; rememberMe: boolean }
ה. כתבו פונקציה initForm גנרית שמקבלת אובייקט עם ערכים התחלתיים ומחזירה FormFields<T>:
let form = initForm({ username: "", password: "", rememberMe: false });
// each field becomes { value: ""/false, error: null, touched: false, dirty: false }
ו. כתבו פונקציה validateForm שמקבלת FormFields<T> ואובייקט של validators (מפתח -> פונקציה שמקבלת ערך ומחזירה string | null), ומחזירה FormErrors<T>.