ميزات TypeScript 5.0+ الثورية
يمثل TypeScript 5.x معلماً رئيسياً مع ديكوراتورات ECMAScript ومعاملات النوع الثابت وتحسينات كبيرة في الأداء. يستكشف هذا الدرس أحدث الميزات وأفضل الممارسات للتطوير الحديث بـ TypeScript.
ديكوراتورات ECMAScript (المرحلة 3)
قدم TypeScript 5.0 دعماً لاقتراح ديكوراتورات ECMAScript الجديد، والذي يختلف عن الديكوراتورات التجريبية:
// تمكين في tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"experimentalDecorators": false // استخدم الديكوراتورات القياسية
}
}
ديكوراتورات الفئة:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class BugReport {
type = "report";
title: string;
constructor(title: string) {
this.title = title;
}
}
// الفئة الآن مغلقة - لا يمكن إضافة خصائص
const report = new BugReport("Memory leak");
// report.newProperty = "value"; // خطأ في الوضع الصارم
ديكوراتورات الطريقة:
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with:`, args);
const result = originalMethod.apply(this, args);
console.log(`Result:`, result);
return result;
};
return descriptor;
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3);
// السجلات:
// Calling add with: [2, 3]
// Result: 5
ديكوراتورات الوصول:
function configurable(value: boolean) {
return function(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
descriptor.configurable = value;
};
}
class Point {
private _x: number;
constructor(x: number) {
this._x = x;
}
@configurable(false)
get x() {
return this._x;
}
set x(value: number) {
this._x = value;
}
}
معاملات النوع الثابت (TypeScript 5.0)
تحافظ معاملات النوع الثابت على الأنواع الحرفية وتنشئ استنتاج أكثر دقة:
// بدون const
function makeArray<T>(items: T[]): T[] {
return items;
}
const arr1 = makeArray([1, 2, 3]);
// النوع: number[]
// مع const
function makeConstArray<const T>(items: T[]): T[] {
return items;
}
const arr2 = makeConstArray([1, 2, 3]);
// النوع: readonly [1, 2, 3]
قوي لكائنات التكوين:
function createConfig<const T extends Record<string, any>>(config: T): T {
return config;
}
const config = createConfig({
apiUrl: "https://api.example.com",
timeout: 5000,
retries: 3
});
// النوع هو:
// {
// readonly apiUrl: "https://api.example.com";
// readonly timeout: 5000;
// readonly retries: 3;
// }
// هذا يمكن فحص النوع الدقيق
function connect(url: "https://api.example.com") {
// التنفيذ
}
connect(config.apiUrl); // ✓ يعمل! النوع حرفي دقيق
عامل 'satisfies' (TypeScript 4.9+)
التحقق من الأنواع دون توسيعها:
type Color = "red" | "green" | "blue";
interface Theme {
primary: Color;
secondary: Color;
}
// بدون satisfies - يفقد الأنواع الحرفية
const theme1: Theme = {
primary: "red",
secondary: "blue"
};
// theme1.primary له نوع Color (وليس "red")
// مع satisfies - يحتفظ بالأنواع الحرفية
const theme2 = {
primary: "red",
secondary: "blue"
} satisfies Theme;
// theme2.primary له نوع "red"
// لا يزال يلتقط الأخطاء
const invalid = {
primary: "red",
secondary: "yellow" // خطأ: "yellow" غير قابل للتعيين إلى Color
} satisfies Theme;
قوي للتحقق من التكوين:
type Route = {
path: string;
method: "GET" | "POST" | "PUT" | "DELETE";
handler: Function;
};
const routes = {
getUser: {
path: "/users/:id",
method: "GET",
handler: () => {}
},
createUser: {
path: "/users",
method: "POST",
handler: () => {}
}
} satisfies Record<string, Route>;
// نوع routes.getUser.method هو "GET" (وليس "GET" | "POST" | "PUT" | "DELETE")
// لكننا لا زلنا نحصل على التحقق من أن جميع المسارات تطابق نوع Route
ملاحظة: استخدم satisfies عندما تريد التحقق من النوع دون التوسيع. استخدم التعليقات التوضيحية للنوع عندما تريد توسيع الأنواع بشكل صريح.
إعلانات Using (TypeScript 5.2)
إدارة الموارد الصريحة مع التنظيف التلقائي:
// إعلان مورد قابل للتخلص
class FileHandle implements Disposable {
constructor(private path: string) {
console.log(`Opening ${path}`);
}
write(data: string): void {
console.log(`Writing to ${this.path}: ${data}`);
}
[Symbol.dispose](): void {
console.log(`Closing ${this.path}`);
}
}
// إعلان using - تنظيف تلقائي
{
using file = new FileHandle("data.txt");
file.write("Hello, World!");
// يتم التخلص من file تلقائياً في نهاية الكتلة
}
// السجلات: "Closing data.txt"
مثالي لاتصالات قاعدة البيانات:
class DatabaseConnection implements AsyncDisposable {
constructor(private connectionString: string) {}
async connect(): Promise<void> {
console.log(`Connecting to ${this.connectionString}`);
}
async query(sql: string): Promise<any[]> {
console.log(`Executing: ${sql}`);
return [];
}
async [Symbol.asyncDispose](): Promise<void> {
console.log(`Disconnecting from ${this.connectionString}`);
}
}
async function queryDatabase() {
await using db = new DatabaseConnection("localhost:5432");
await db.connect();
const users = await db.query("SELECT * FROM users");
return users;
// يتم التخلص من db تلقائياً هنا
}
سمات الاستيراد (TypeScript 5.3)
حدد تأكيدات الاستيراد للوحدات غير JavaScript:
// استيراد JSON مع تأكيد النوع
import config from "./config.json" with { type: "json" };
// استيراد وحدات CSS
import styles from "./styles.css" with { type: "css" };
// تكوين آمن للأنواع
type Config = {
apiUrl: string;
timeout: number;
};
const typedConfig: Config = config;
تحسين الاستنتاج لسلاسل القوالب
TypeScript 5.0+ لديه استنتاج أفضل لأنواع سلاسل القوالب:
// بناء مساعدي المسار الآمن للأنواع
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type Route = `/${string}`;
function createRoute<M extends HttpMethod, R extends Route>(
method: M,
route: R
): `${M} ${R}` {
return `${method} ${route}`;
}
const getUserRoute = createRoute("GET", "/users/:id");
// النوع: "GET /users/:id"
const createUserRoute = createRoute("POST", "/users");
// النوع: "POST /users"
// مطابقة مسار آمنة للأنواع
function matchRoute(route: "GET /users/:id" | "POST /users") {
// التنفيذ
}
matchRoute(getUserRoute); // ✓ صحيح
matchRoute(createUserRoute); // ✓ صحيح
// matchRoute("GET /invalid"); // ✗ خطأ
أداء فحص الأنواع أسرع
قدم TypeScript 5.0 تحسينات كبيرة في الأداء:
// تحسينات tsconfig.json
{
"compilerOptions": {
// حل أسرع
"moduleResolution": "bundler",
// تخطي فحص المكتبة للسرعة
"skipLibCheck": true,
// بناءات أسرع مع التزايدي
"incremental": true,
// افترض أن التغييرات تؤثر فقط على التبعيات المباشرة
"assumeChangesOnlyAffectDirectDependencies": true
}
}
تحسينات بيان Switch
فحص استنفاد أفضل في بيانات switch:
type Status = "pending" | "approved" | "rejected";
function handleStatus(status: Status): string {
switch (status) {
case "pending":
return "Waiting for approval";
case "approved":
return "Request approved";
case "rejected":
return "Request rejected";
// إذا أضفت حالة جديدة، سيحدث خطأ في TypeScript هنا
}
// TypeScript يعلم أن هذا غير قابل للوصول
}
// أفضل مع فحص استنفاد
function handleStatusExhaustive(status: Status): string {
switch (status) {
case "pending":
return "Waiting for approval";
case "approved":
return "Request approved";
case "rejected":
return "Request rejected";
default:
// هذا يضمن أننا نتعامل مع جميع الحالات
const _exhaustive: never = status;
return _exhaustive;
}
}
ميزات TypeScript 5.4+
نوع الأداة NoInfer:
// منع الاستنتاج في مواضع محددة
function createCollection<T>(
initial: T[],
additional: NoInfer<T>[]
): T[] {
return [...initial, ...additional];
}
const nums = createCollection([1, 2, 3], [4, 5, 6]); // ✓ صحيح
// const invalid = createCollection([1, 2], ["3"]); // ✗ خطأ
تحسين التضييق في الدوال العامة:
function processValue<T>(value: T): void {
if (typeof value === "string") {
// TypeScript 5.4+ يضيق T إلى string هنا
console.log(value.toUpperCase());
} else if (typeof value === "number") {
// وإلى number هنا
console.log(value.toFixed(2));
}
}
تحسينات TypeScript Compiler API
بناء أدوات مخصصة مع مترجم TypeScript:
import * as ts from "typescript";
// إنشاء برنامج من التكوين
const configPath = ts.findConfigFile(
"./",
ts.sys.fileExists,
"tsconfig.json"
);
const { config } = ts.readConfigFile(configPath!, ts.sys.readFile);
const { options, fileNames } = ts.parseJsonConfigFileContent(
config,
ts.sys,
"./"
);
const program = ts.createProgram(fileNames, options);
const checker = program.getTypeChecker();
// تحليل الأنواع في قاعدة الشفرة الخاصة بك
program.getSourceFiles().forEach(sourceFile => {
if (!sourceFile.isDeclarationFile) {
ts.forEachChild(sourceFile, visit);
}
});
function visit(node: ts.Node) {
if (ts.isFunctionDeclaration(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
console.log(`Found function: ${symbol?.getName()}`);
}
ts.forEachChild(node, visit);
}
ميزات TypeScript المستقبلية (مقترحة)
الميزات القادمة لمشاهدتها:
- إدارة الموارد الصريحة: توسيع إعلانات using/await using
- الحساب على مستوى النوع: إجراء الحسابات على مستوى النوع
- مطابقة الأنماط: التفكيك المتقدم مع تضييق النوع
- أنواع التأثير: تتبع الآثار الجانبية في نظام الأنواع
- الأنواع الاسمية: دعم من الدرجة الأولى للكتابة الاسمية
- الأنواع عالية النوع: التجريد عبر منشئي الأنواع
أفضل الممارسات لـ TypeScript 5.x
// 1. استخدم معاملات النوع الثابت للحفاظ على الحرفية
const routes = createRoutes([
{ path: "/users", method: "GET" },
{ path: "/posts", method: "POST" }
] as const);
// 2. استفد من satisfies للتحقق دون التوسيع
const config = {
api: { url: "https://api.com", timeout: 5000 },
features: { darkMode: true, analytics: false }
} satisfies AppConfig;
// 3. استخدم إعلانات using لإدارة الموارد
async function processFile(path: string) {
await using file = await openFile(path);
// تنظيف تلقائي
}
// 4. فضل الاستيرادات للأنواع فقط
import type { User, Product } from "./types";
import { fetchUser, fetchProduct } from "./api";
// 5. استخدم NoInfer للتحكم في استنتاج النوع
function merge<T>(base: T, override: NoInfer<Partial<T>>): T {
return { ...base, ...override };
}
استراتيجية الترحيل إلى TypeScript 5.x
// 1. تحديث package.json
{
"devDependencies": {
"typescript": "^5.4.0"
}
}
// 2. تحديث tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"moduleResolution": "bundler",
// تعطيل الديكوراتورات التجريبية إذا كنت تستخدم القياسية
"experimentalDecorators": false
}
}
// 3. اختبر البناء الخاص بك
npm install
npm run build
npm run type-check
// 4. استبدل الأنماط المهجورة
// القديم: الديكوراتورات التجريبية
// الجديد: الديكوراتورات القياسية (إذا كنت تستخدم الديكوراتورات)
// القديم: تأكيدات النوع في كل مكان
// الجديد: عامل satisfies
// القديم: التنظيف اليدوي للموارد
// الجديد: إعلانات using
TypeScript Playground والتصحيح
استخدم أدوات التصحيح الحديثة:
// تمكين التشخيصات المتقدمة
{
"compilerOptions": {
"extendedDiagnostics": true,
"generateTrace": "./trace"
}
}
// تحليل التتبع مع:
# npm install -g @typescript/analyze-trace
# analyze-trace ./trace
مثال من العالم الحقيقي: تطبيق TypeScript حديث
// config.ts
export const appConfig = {
api: {
baseUrl: "https://api.example.com",
timeout: 5000,
retries: 3
},
features: {
analytics: true,
darkMode: false
},
routes: {
home: "/",
users: "/users",
profile: "/users/:id"
}
} as const satisfies AppConfig;
// النوع محفوظ بالضبط
type ApiUrl = typeof appConfig.api.baseUrl;
// النوع: "https://api.example.com"
// database.ts
class Database implements AsyncDisposable {
constructor(private config: DatabaseConfig) {}
async [Symbol.asyncDispose](): Promise<void> {
await this.disconnect();
}
async query<T>(sql: string): Promise<T[]> {
// التنفيذ
return [];
}
}
// الاستخدام مع التنظيف التلقائي
async function getUsers() {
await using db = new Database(dbConfig);
return await db.query<User>("SELECT * FROM users");
// db قطع الاتصال تلقائياً
}
// api.ts
function createApiClient<const Routes extends Record<string, Route>>(
baseUrl: string,
routes: Routes
) {
return {
request: <K extends keyof Routes>(
route: K,
...args: Routes[K] extends { params: infer P } ? [P] : []
) => {
// التنفيذ
}
};
}
const api = createApiClient("https://api.com", {
getUser: { path: "/users/:id", method: "GET", params: ["id"] },
createPost: { path: "/posts", method: "POST", params: [] }
} as const);
// استدعاءات API آمنة تماماً للأنواع
api.request("getUser", "user-123"); // ✓ صحيح
api.request("createPost"); // ✓ صحيح
// api.request("getUser"); // ✗ خطأ: معاملات مفقودة
تحذير: ليست جميع ميزات TypeScript 5.x مدعومة في جميع بيئات التشغيل. تحقق من التوافق مع بيئتك المستهدفة (Node.js، المتصفحات، Deno) قبل استخدام ميزات متقدمة مثل الديكوراتورات وإعلانات using.
موارد المجتمع
ابق محدثاً:
- المدونة الرسمية: devblogs.microsoft.com/typescript
- GitHub: github.com/microsoft/TypeScript
- Playground: typescriptlang.org/play
- Discord: TypeScript Community Discord
- Twitter: @typescript للإعلانات
- DefinitelyTyped: github.com/DefinitelyTyped/DefinitelyTyped
المشروع النهائي:
- أنشئ تطبيق TypeScript 5.4+ حديث باستخدام معاملات النوع الثابت
- نفذ إدارة الموارد مع إعلانات using
- استخدم عامل satisfies لجميع كائنات التكوين
- أنشئ عميل API آمن للأنواع مع أنواع حرفية دقيقة
- نفذ الديكوراتورات للتسجيل والتحقق (إذا كنت تستخدم الديكوراتورات القياسية)
- قم بإعداد فحص شامل للأنواع مع الوضع الصارم
- قس تغطية الأنواع واهدف إلى 95٪+
- وثق بنية نظام الأنواع والأنماط المستخدمة
تهانينا! لقد أكملت دورة TypeScript. لديك الآن إتقان لـ TypeScript الحديث بما في ذلك الأنواع المتقدمة والعموميات والديكوراتورات وأحدث ميزات 5.x. استمر في بناء تطبيقات آمنة للأنواع وابق محدثاً مع خارطة طريق TypeScript!