انواع پیشرفته (Advanced Types)
در این صفحه با «انواع پیشرفته تایپ اسکریپت» آشنا می شوی. منظور از نوع پیشرفته، ابزارهای دقیق برای توصیف داده هاست. بنابراین خطاها کمتر می شوند و کدت قابل اعتمادتر می شود. مثلا مثل قانون های دقیق در دبیرستان که تکلیف همه چیز را روشن می کند.
مرور کوتاه انواع پیشرفته
ویژگی ها شامل نوع های نگاشتی، شرطی، رشته ای الگو، انواع کمکی، بازگشتی و سرنخ گیری با infer است. هر کدام مشکلی خاص را حل می کنند. پس قدم به قدم جلو برو.
Mapped Types (نوع های نگاشتی)
«نگاشتی» یعنی روی همه ویژگی های یک نوع، یک الگوی مشترک اعمال کنی؛ مثل برچسب زدن همه پوشه ها.
// Convert all properties to boolean
type Flags<T> = {
[K in keyof T]: boolean;
};
interface User {
id: number;
name: string;
email: string;
}
type UserFlags = Flags<User>;
// { id: boolean; name: boolean; email: boolean; }
Mapped Modifiers (اصلاح گرها)
با + و - می توانی readonly و ? را اضافه یا حذف کنی؛ مثل قفل زدن یا بازکردن کشوها.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type OptionalTodo = {
[K in keyof Todo]?: Todo[K];
};
type Concrete<T> = {
-readonly [K in keyof T]-?: T[K];
};
type ReadonlyRequired<T> = {
+readonly [K in keyof T]-?: T[K];
};
Key Remapping (تغییر نام کلید)
می توانی کلیدها را با as تغییر نام دهی یا فیلتر کنی؛ مثل تغییر عنوان پوشه ها.
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type MethodsOnly<T> = {
[K in keyof T as T[K] extends Function ? K : never]: T[K];
};
Conditional Types (نوع های شرطی)
نوع شرطی یعنی انتخاب نوع بر اساس شرط؛ مثل اگر-وگرنه سر کلاس.
type IsString<T> = T extends string ? true : false;
type A = IsString<string>;
type B = IsString<number>;
type ArrayElement<T> = T extends (infer U)[] ? U : never;
type Numbers = ArrayElement<number[]>;
infer (گرفتن نوعِ پنهان)
infer یعنی از داخل یک نوع، بخشی را بیرون بکشیم؛ مثل پیدا کردن الگو.
type FnReturn<T> = T extends (...args: any[]) => infer R ? R : any;
type FnParams<T> = T extends (...args: infer P) => any ? P : never;
type CtorParams<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
type InstanceOf<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
توزیع روی Union ها
گاهی شرطی ها روی اعضای Union پخش می شوند. با براکت می توانی پخش شدن را کنترل کنی.
type ToArrayNonDist<T> = T extends any ? T[] : never;
type StrOrNumArr = ToArrayNonDist<string | number>;
type ToArray<T> = [T] extends [any] ? T[] : never;
type StrOrNumArr2 = ToArray<string | number>;
type FilterStrings<T> = T extends string ? T : never;
type Letters = FilterStrings<'a' | 'b' | 1 | 2 | 'c'>;
Template Literal Types (رشته های الگو)
با Template Literal می توانی الگوی رشته بسازی؛ مثل «قرمز-کوچک».
type Greeting = `Hello, ${string}`;
const validGreeting: Greeting = 'Hello, World!';
// const invalidGreeting: Greeting = 'Hi there!';
type Color = 'red' | 'green' | 'blue';
type Size = 'small' | 'medium' | 'large';
type Style = `${Color}-${Size}`;
دستکاری رشته ای
با Uppercase و Capitalize و… می توانی حروف را تغییر دهی؛ مثل تیترکردن.
type T1 = Uppercase<'hello'>;
type T2 = Lowercase<'WORLD'>;
type T3 = Capitalize<'typescript'>;
type T4 = Uncapitalize<'TypeScript'>;
type EventType = 'click' | 'change' | 'keydown';
type EventHandler = `on${Capitalize<EventType>}`;
الگوهای پیشرفته
می توانی پارامتر مسیر را استخراج کنی یا API تولید کنی؛ مثل ساخت نقشه راه.
type ExtractRouteParams<T> = T extends `${string}:${infer Param}/${infer Rest}`
? { [K in Param | keyof ExtractRouteParams<`${Rest}`>]: string }
: T extends `${string}:${infer Param}`
? { [K in Param]: string }
: {};
type Params = ExtractRouteParams<'/users/:userId/posts/:postId'>;
type EventMap = {
click: { x: number; y: number };
change: string;
keydown: { key: string; code: number };
};
type EventHandlers = {
[K in keyof EventMap as `on${Capitalize<K>}`]: (event: EventMap[K]) => void;
};
Utility Types (انواع کمکی)
انواع کمکی آماده هستند و تغییرات رایج را ساده می کنند؛ مثل ابزارهای جعبه ابزار.
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
type PartialUser = Partial<User>;
type RequiredUser = Required<PartialUser>;
type ReadonlyUser = Readonly<User>;
type UserPreview = Pick<User, 'id' | 'name'>;
type UserWithoutEmail = Omit<User, 'email'>;
type UserId = User['id'];
type UserKeys = keyof User;
Utility های پیشرفته
با Exclude و Extract اتحادها را پالایش کن و نوع های سفارشی بساز.
type NonNullable<T> = T extends null | undefined ? never : T;
type Numbers = 1 | 2 | 3 | 'a' | 'b';
type JustNumbers = Exclude<Numbers, string>;
type JustStrings = Extract<Numbers, string>;
type A = { a: string; b: number; c: boolean };
type B = { a: string; b: number };
type C = Omit<A, keyof B>;
type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
Recursive Types (نوع های بازگشتی)
بازگشتی یعنی نوع به خودش اشاره کند؛ مثل درخت پوشه ها در رایانه.
type BinaryTree<T> = {
value: T;
left?: BinaryTree<T>;
right?: BinaryTree<T>;
};
type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
type Comment = {
id: number;
content: string;
replies: Comment[];
createdAt: Date;
};
الگوهای بازگشتی پیشرفته
لیست پیوندی، درخت پوشه و ماشین حالت را می توان دقیق مدل کرد.
type LinkedList<T> = {
value: T;
next: LinkedList<T> | null;
};
type File = {
type: 'file';
name: string;
size: number;
};
type Directory = {
type: 'directory';
name: string;
children: (File | Directory)[];
};
type State = {
value: string;
transitions: {
[event: string]: State;
};
};
type RecursiveFunction<T> = (x: T | RecursiveFunction<T>) => void;
بهترین تمرین ها
ساده شروع کن، سپس دقیق شو. برای خوانایی کامنت بگذار. همچنین از انواع کمکی آماده استفاده کن تا چرخ را دوباره اختراع نکنی.
دام های رایج
پخش شدن شرطی روی Union ها می تواند غافلگیرکننده باشد. همچنین نوع های بسیار عمیق، کامپایل را کند می کنند. پس نوع ها را خرد کن و مستند کن.
جمع بندی سریع
- نوع های نگاشتی، همه ویژگی ها را یک جا تغییر می دهند.
- نوع های شرطی، انتخاب هوشمند انجام می دهند.
- Template Literal، رشته ها را قانون مند می کند.
- Utility Types، میانبرهای کاربردی می دهند.
- بازگشتی ها، ساختارهای درختی را دقیق می سازند.
برای ادامه انواع پیشرفته تایپ اسکریپت به همراه نگهبان های نوع، صفحه Type Guards را ببین. همچنین برای ابزارها، ابزارها را مرور کن.