TypeScript: پیشرفته
TypeScript: پیشرفته؛ آموزش مسیر فرانتاند به زبان ساده، همراه با مثال و خروجی.
Generics
نوعهای پارامتری، برای کدی که روی نوعهای مختلف کار میکنه.
function first<T>(arr: T[]): T | undefined { return arr[0]; }
first([1, 2]); // number | undefined
first(["a"]); // string | undefined
interface ApiResponse<T> { data: T; error?: string }
const r: ApiResponse<{ id: number }> = { data: { id: 1 } };
// محدودیت
function len<T extends { length: number }>(x: T) { return x.length; }
len("abc"); len([1, 2]);
// مقدار پیشفرض
type Box<T = string> = { value: T };
keyof، typeof، indexed access
type User = { id: number; name: string };
type Keys = keyof User; // "id" | "name"
type Name = User["name"]; // string
function get<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }
get({ a: 1, b: "x" }, "b"); // string
const config = { port: 3000, host: "x" };
type Config = typeof config; // { port: number; host: string }
Utility Types
type U = { id: number; name: string; email?: string };
Partial<U> // همه اختیاری
Required<U> // همه اجباری
Readonly<U> // همه فقطخواندنی
Pick<U, "id" | "name"> // انتخاب
Omit<U, "email"> // حذف
Record<"a" | "b", number> // { a: number; b: number }
Exclude<"a" | "b", "a"> // "b"
Extract<string | number, number> // number
NonNullable<string | null> // string
ReturnType<typeof fn> // نوع خروجی تابع
Parameters<typeof fn> // tuple پارامترها
Awaited<Promise<string>> // string
Mapped Types
type Flags<T> = { [K in keyof T]: boolean };
type Getters<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
type Mutable<T> = { -readonly [K in keyof T]-?: T[K] }; // حذف readonly و ?
Conditional Types و infer
type IsString<T> = T extends string ? true : false;
type A = IsString<"x">; // true
type ElementOf<T> = T extends (infer E)[] ? E : never;
type N = ElementOf<number[]>; // number
type Unwrap<T> = T extends Promise<infer R> ? R : T;
Template Literal Types
type Event = "click" | "focus";
type Handler = `on${Capitalize<Event>}`; // "onClick" | "onFocus"
type Route = `/users/${number}`;
Type Guards
function isString(x: unknown): x is string { return typeof x === "string"; }
function assertDefined<T>(x: T | undefined): asserts x is T {
if (x === undefined) throw new Error("undefined!");
}
satisfies
چک نوع بدون از دست دادن نوع دقیق مقدار:
const palette = {
red: [255, 0, 0],
green: "#00ff00",
} satisfies Record<string, string | number[]>;
palette.red.map(n => n); // هنوز آرایه است
palette.green.toUpperCase(); // هنوز رشته است
Overload
function parse(x: string): number;
function parse(x: number): string;
function parse(x: string | number) { return typeof x === "string" ? Number(x) : String(x); }
Module و Declaration
import type { User } from "./types"; // فقط نوع، در JS حذف میشه
export type { User };
declare module "*.svg" { const url: string; export default url; } // نوع برای import فایل
declare global { interface Window { dataLayer: unknown[] } }
الگوهای کاربردی در فرانتاند
// نوع props در React
type ButtonProps = {
variant?: "primary" | "ghost";
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
} & React.ComponentPropsWithoutRef<"button">;
// نوعدار کردن fetch
async function api<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(String(res.status));
return res.json() as Promise<T>;
}
res.json() اعتبارسنجی نمیکنه؛ برای دادهی خارجی از Zod / Valibot استفاده کن:
import { z } from "zod";
const UserSchema = z.object({ id: z.number(), name: z.string() });
type User = z.infer<typeof UserSchema>;
const user = UserSchema.parse(await res.json()); // خطا اگه شکل داده اشتباه باشه
نکات
strictروشن،anyممنوع (ازunknownاستفاده کن).- نوعها رو از دادهها استنتاج کن (
typeof,z.infer) بهجای تکرار. - پیامهای خطای TS رو از آخرین خط بخون.
- TS فقط compile-time است؛ validation زمان اجرا جداست.
تمرین
۱. DeepPartial<T> بنویس. ۲. تابع pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] رو پیاده کن. ۳. با Zod پاسخ یک API واقعی رو اعتبارسنجی کن.