تعيين المخطط إلى النوع
افهموا كيف تصبح تعريفات الجداول أنواع TypeScript
تعيين المخطط إلى النوع درس مجاني في TypeScript Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في TypeScript Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة TypeScript Academy 4 دروس في المجموع.
من تعريف الجدول إلى نوع الصف
يتيح لك ORM الآمن من حيث الأنواع وصف جدول قاعدة البيانات مرة واحدة واشتقاق نوع صف TypeScript منه تلقائيًا. ولن تضطر أبدًا إلى كتابة بنية الصف يدويًا؛ إذ تُحسب من تعريفات الأعمدة.
نستخدم في هذا الدرس pgTable بأسلوب Drizzle مثالًا تطبيقيًا مستمرًا.
تعريف جدول
الجدول هو كائن يربط أسماء الأعمدة بمنشئات الأعمدة. ويشفّر كل منشئ نوع SQL، إضافةً إلى معدّلات مثل notNull أو primaryKey.
import { pgTable, serial, text, integer, boolean } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
age: integer("age"),
isAdmin: boolean("is_admin").notNull(),
});استدلال نوع العمود
يحمل كل منشئ أعمدة نوعًا وهميًا يصف القيمة التي ينتجها. ويُطابق serial وinteger النوع number، بينما يُطابق text النوع string، ويُطابق boolean النوع boolean.
كما يتتبع المنشئ ما إذا كان العمود يقبل القيمة الفارغة.
import { InferSelectModel } from "drizzle-orm";
// Row type inferred from the table above
type User = InferSelectModel<typeof users>;
// {
// id: number;
// name: string;
// age: number | null; // not notNull -> nullable
// isAdmin: boolean;
// }notNull يتحكم في القابلية لـ null
العامل الأهم على الإطلاق في تحديد نوع الصف هو notNull(). فالعمود الذي لا يحتوي عليه يصبح T | null في النوع المستنتج، لأن SQL تسمح بالقيمة NULL افتراضيًا.
const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: text("title").notNull(), // string
subtitle: text("subtitle"), // string | null
});
type Post = InferSelectModel<typeof posts>;
// { id: number; title: string; subtitle: string | null }نماذج Select مقابل Insert
يختلف نوع الصف المستخدم للقراءة (select) عن النوع المستخدم للكتابة (insert). عند الإدراج، تصبح الأعمدة التي لها قيم افتراضية أو زيادة تلقائية اختيارية.
import { InferInsertModel } from "drizzle-orm";
type NewUser = InferInsertModel<typeof users>;
// {
// id?: number; // serial has a default -> optional
// name: string;
// age?: number | null;
// isAdmin: boolean;
// }كيفية عمل الاستنتاج
في الخلفية، كل منشئ أعمدة هو فئة عامة مثل PgColumn<{ data: number; notNull: true }>. ويمر نوع معيّن عبر كل مفتاح في الجدول ويقرأ تلك العلامات.
// Simplified mental model of the inference
type InferRow<T> = {
[K in keyof T]: T[K] extends { _: { data: infer D; notNull: infer N } }
? N extends true ? D : D | null
: never;
};الأنواع Enum والأنواع المخصصة
تُحوَّل أعمدة اتحاد السلاسل إلى اتحادات حرفية، وليس إلى string فقط. وهذا يعني أن قيمة الحالة غير الصالحة تؤدي إلى خطأ في وقت الترجمة.
import { pgEnum } from "drizzle-orm/pg-core";
export const roleEnum = pgEnum("role", ["user", "admin", "owner"]);
export const members = pgTable("members", {
id: serial("id").primaryKey(),
role: roleEnum("role").notNull(), // "user" | "admin" | "owner"
});القيم الافتراضية
يجعل .default() العمود اختياريًا عند الإدراج، لكنه يُبقيه موجودًا عند الاختيار. ويشفّر نظام الأنواع معلومة «له قيمة افتراضية»، حتى يغيّر الاختيارية فقط في الموضع المناسب.
const events = pgTable("events", {
id: serial("id").primaryKey(),
createdAt: text("created_at").notNull().default("now()"),
});
// Select: createdAt is string
// Insert: createdAt is optional (default fills it)لماذا يهم هذا
بما أن نوع الصف مشتق، فإن تغيير المخطط يحدّث تلقائيًا نوع كل نتيجة استعلام. أعيدوا تسمية عمود، وسيشير المترجم إلى كل مرجع قديم. فلا يوجد مصدر ثانٍ للحقيقة يمكن أن ينحرف عن المصدر الأساسي.
مثال صغير متكامل من البداية إلى النهاية
بتجميع الأجزاء: عرّفوا العنصر مرة واحدة، واستنتجوا النوع، واستخدموه بوصفه العقد الخاص بدالة المستودع.
type User = InferSelectModel<typeof users>;
async function findUser(id: number): Promise<User | undefined> {
// db.query returns rows already typed as User
const rows = await db.select().from(users).where(eq(users.id, id));
return rows[0];
}مأزق: نسيان notNull
إذا نسيتم إضافة notNull() إلى عمود مطلوب فعليًا، فسيصبح النوع المستنتج T | null، ويفرض عمليات تحقق غير ضرورية من null في أنحاء الشيفرة. احرصوا على أن يعكس المخطط الواقع بدقة.
تحقق سريع
اختبروا مدى فهمكم لعملية تحويل المخطط إلى نوع.
مراجعة
تعلّمتم أن تعريف الجدول هو المصدر الوحيد للحقيقة: تحمل منشئات الأعمدة أنواعًا وهمية، وتمر الأنواع المعيّنة عبر الجدول لبناء نوع الصف، ويتحكم notNull() في القابلية لـ null، كما يختلف نموذجا select وinsert في الاختيارية. غيّروا المخطط، وستتبع ذلك تلقائيًا أنواع جميع النتائج.
الأسئلة الشائعة
هل درس «تعيين المخطط إلى النوع» مجاني؟
نعم — نص درس «تعيين المخطط إلى النوع» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة TypeScript Academy، انتقل إلى CoddyKit PRO. تتضمن دورة TypeScript Academy 4 دروس في المجموع.
ماذا ستتعلم في «تعيين المخطط إلى النوع»؟
افهموا كيف تصبح تعريفات الجداول أنواع TypeScript تتمرن على TypeScript Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ TypeScript Academy؟
لا تُشترط خبرة سابقة. TypeScript Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «تعيين المخطط إلى النوع»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس TypeScript Academy هذا؟
نعم. كل درس في TypeScript Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تعيين المخطط إلى النوع
- إنشاء الاستعلامات الآمن نوعيًا
- استنتاج أشكال نتائج الاستعلام
- العلاقات وعمليات الربط مع الأنواع