TypeScript structure
خب TypeScript فقط «JavaScript با Type» نیست؛
بلکه یک Type System قدرتمند است که به ما کمک میکند:
- زودتر خطاها را ببینیم
- کد قابلاعتمادتر بنویسیم
- و Refactor بدون ترس انجام دهیم
- و در پروژههای بزرگ، sanity خودمان را حفظ کنیم
Type Annotation (تعیین نوع)
let price: number = 100;
let title: string = "Book";
Array Types
let numbers: number[]
= [1, 2, 3]
;
// Or Generic:
let users: Array<string> = ["Ali", "Reza"]
;
Tuple
- آرایه با طول و نوع ثابت:
- ترتیب مقادیر مهم است.
let user: [number, string]
= [1, "Ali"]
;
Any Type
- اجازه استفاده از هر نوع داده:
- در واقع TypeScript ،
anyرا خاموش میکند
let data: any = 5;
data = "Hello";
data = true;
⚠️ توصیه: تا حد ممکن استفاده نشود.
Unknown Type
- امنتر از any:
- اما
unknownشما را مجبور میکند Type Narrowing انجام دهید.
let value: unknown = "Hi";
if (typeof value === "string") {
console.log(value.toUpperCase());
}
Void and Never
- Void : برای توابع بدون خروجی
function log(msg: string): void {
console.log(msg);
}
- Never : برای توابعی که هرگز خاتمه نمییابند
function error(msg: string): never {
throw new Error(msg);
}
Union Types
- پذیرش چند نوع
let id: number | string;
id = 10;
id = "ABC";
Intersection Types
- ترکیب چند نوع
type A = { name: string };
type B = { age: number };
type C = A & B;
Type Alias
- تعریف نوع سفارشی
type User = {
id: number;
name: string;
};
Interface
- تعریف ساختار اشیاء
interface User {
id: number;
name: string;
}
// Extend
interface Admin extends User {
role: string;
}
Optional و Readonly
// Optional
interface User {
name: string;
age?: number;
}
// Edit Form
--------------------------------
// ReadOnly
interface User {
readonly id: number;
}
// Or
type ReadonlyUser = Readonly<User>;
// Not Change Data : جلوگیری از تغییر دیتا.
Function Types
function add(a: number, b: number): number {
return a + b;
}
// Arrow Function
const sum = (a: number, b: number): number => a + b;
Type Assertion
- تبدیل نوع
let input = document.getElementById("app") as HTMLElement;
Enum
خب Enum یعنی مجموعهای از مقادیر ثابت با نام مشخص که در TypeScript خیلی استفاده میشه
enum Direction {
Up,
Down,
Left,
Right,
}
// استفاده
let move: Direction = Direction.Up;
// خروجی پشت صحنه JS
{
Up: 0,
Down: 1,
Left: 2,
Right: 3
}
// Enum با مقدار مشخص
enum Status {
Success = 200,
NotFound = 404,
ServerError = 500
}
// Enum رشتهای
enum Role {
Admin = "ADMIN",
User = "USER"
}
Generics
خب Generics اجازه میدهد کدی بنویسیم که:
- مستقل از نوع داده باشد
- و Type-Safe باقی بماند
- قابل استفاده مجدد باشد
async function fetcher<T>(url: string): Promise<T> {
const res = await fetch(url);
return res.json();
}
type User = { id: number; name: string };
const user = await fetcher<User>("/api/user");
// يه مثال كاربردى
function safeLocalStorage<T>(key: string, defaultValue: T) {
return {
get: (): T => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
},
set: (value: T) => {
localStorage.setItem(key, JSON.stringify(value));
},
};
}
// استفاده
const userStorage = safeLocalStorage("user", { name: "", age: 0 });
userStorage.set({ name: "ali", age: 25 }); // فقط آبجکت با همین ساختار قبول میشه
const iser = userStorage.get(); // تایپ برگشتی هم دقیقا همون ساختار رو داره
Utility Types
// Partial
type UserPartial = Partial<User>;
// Required
type UserRequired = Required<User>;
// Pick
type UserName = Pick<User, "name">;
// Omit
type UserWithoutId = Omit<User, "id">;
| Use Case واقعی | Utility |
|---|---|
| Edit Form | Partial |
| Validation | Required |
| DTO / API Response | Pick |
| Remove Sensitive Fields | Omit |
| Config / Permission | Record |
keyof Operator
type UserKeys = keyof User;
// Export
"id" | "name";
typeof Operator
const person = {
name: "Ali",
age: 30,
};
type PersonType = typeof person;
Conditional Types
ميتونيم براساس شرط، تايپ هاى مختلف بسازيم. انعطاف پذيرى در تعريف تايپ يعنى همين.
type ApiResponse<T> = T extends "error"
? { status: 400; message: string }
: { status: 200; data: any };
// استفاده
type ErrorResponse = ApiResponse<"error">; // status: 400
type SuccessResponse = ApiResponse<"success">; // status: 200
Template Literal Types
يكى از قابليت هاى جذاب تايپ اسكرييت كه خيليا نميشناسن. باهاش ميشه تايپ هاى يويا ساخت.
type Endpoint = `api/v1/${string}`;
// حالا فقط آدرس هاى معتبر قبول ميشن
const userEndpoint: Endpoint = "api/v1/users"; // درست
const wrongEndpoint: Endpoint = "v1/users"; // خطا
Type Guards
امنيت بيشتر در زمان اجرا. تايپ کاردها كمك ميكنن كدمون امن تر باشه:D
type User = { name: string; age: number };
type Admin = { name: string; permissions: string[]
};
function isAdmin(user: User | Admin): user is Admin {
return "permissions" in user;
}
// استفاده
function handleUser(user: User | Admin) {
if (isAdmin(user)) {
console.log(user.permissions); // حالا خطا نمیده
}
}
Mapped Types
// Optional
type Optional<T> = {
[K in keyof T]
?: T[K]
;
};
// Remove Readonly
type Mutable<T> = {
-readonly [K in keyof T]
: T[K]
;
};
// Transform Property
type Booleanify<T> = {
[K in keyof T]
: boolean;
};
Strict Mode
- فعالسازی حالت سختگیرانه در tsconfig.json
{
"compilerOptions": {
"strict": true
}
}
مزایا:
- کاهش باگ
- بررسی Null
- بررسی Type دقیق
Record Type
permission map ها
config object ها
mapping بین status → behavior
theme / variant / mode ها
وقتی کلیدها محدود و مشخص هستن
ساخت Object تایپ شده
type Roles = "admin" | "user";
const permissions: Record<Roles, string[]
> = {
admin: ["read", "write"]
,
user: ["read"]
,
};
ReturnType
// گرفتن خروجی تابع
function getUser() {
return { id: 1, name: "Ali" };
}
type UserType = ReturnType<typeof getUser>;
Utility Type
خب Utility Type ها برای ساخت type های جدید از type های موجود استفاده میشن.
Partial :
- همه پراپرتی ها آپشنال هستند
interface User {
name: string;
age: number;
}
type UpdateUser = Partial<User>;
// خروجی
{
name?: string
age?: number
}
Required :
- همه پراپرتی ها اجباری هستند
type UserRequired = Required<User>;
Pick :
- فقط بعضی property ها.
type UserName = Pick<User, "name">;
Omit :
- حذف بعضی property ها.
type UserWithoutAge = Omit<User, "age">;
Record :
- ساخت object type.
type UserRoles = Record<string, string>;
Readonly :
- property ها immutable میشن.
type ReadonlyUser = Readonly<User>;