برنامه نویسی

TypeScript Type Negation: How To Forbid of Disa Properties

نفی تایپ در TypeScript به شما اجازه می دهد تا انواعی را ایجاد کنید که به صراحت ویژگی های خاصی را حذف می کنند. معمولاً انواعی را تعریف می کنیم که مشخص می کنند یک شی باید چه ویژگی هایی داشته باشد تا آن نوع را برآورده کند. با نفی نوع، می خواهیم برعکس عمل کنیم: ما مشخص می کنیم که یک شی نباید دارای کدام ویژگی باشد. شما می توانید به این فکر کنید املاک رزرو شده.

بیایید مثال زیر را در نظر بگیریم. ما یک ژنریک داریم createItem تابعی که یک آیتم جدید را در پایگاه داده NoSQL ما وارد می کند (مانند MongoDB، DynamoDB، و غیره). پایگاه داده NoSQL و جداول آن طرح ستونی تعریف شده ای ندارند، به این معنی که آیتم با تمام ویژگی هایش به همان صورت ذخیره می شود. با این حال، برای بازیابی آیتم ها، باید حداقل یک ویژگی را به عنوان کلید اصلی تعریف کنیم (به عنوان مثال در DynamoDB این کلید هش است). این معمولاً یک شناسه به عنوان یک عدد صحیح یا UUID است که می تواند توسط پایگاه داده یا برنامه تعریف شود.

function createItem<TItem extends object>(item: TItem): TItem {
  // Database sets ID
  const newItem = db.insert(item);

  return newItem;
}

// Returns object with id { id: "0d92b425efc9", name: "John", ... }
const user = createItem({ name: "John", email: "[email protected]" });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما می توانیم این تابع را با هر شی جاوا اسکریپت فراخوانی کرده و در پایگاه داده NoSQL خود ذخیره کنیم. اما چه اتفاقی می‌افتد اگر شیئی که به آن منتقل می‌کنیم حاوی یک باشد id ویژگی؟

// What will happen?
//> Will it create a new item?
//> Will it overwrite the item if it exists?
const user = createItem({ id: "0d92b425efc9", name: "John", email: "[email protected]" });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

آنچه در واقع اتفاق می افتد، البته به پایگاه داده بستگی دارد. یک مورد جدید می تواند ایجاد شود، یا یک مورد موجود می تواند بازنویسی شود، یا حتی اگر قرار نباشد یک شناسه خارجی مشخص کنیم، ممکن است یک خطا ایجاد شود. البته، ما می توانیم به سادگی یک چک به آن اضافه کنیم id دارایی و خودمان برای جلوگیری از چنین مواردی خطایی را مطرح کنیم.

function createItem<TItem extends object>(item: TItem): TItem {
  if('id' in item) throw new Error("Item must not contain an ID");
  // Database sets ID
  const newItem = db.insert(item);

  return newItem;
}

// Throws an error
const user = createItem({ id: "0d92b425efc9", name: "John", email: "[email protected]" });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بیایید یک قدم جلوتر برویم و از ژنریک و انواع TypeScript استفاده کنیم تا از وقوع چنین مواردی در وهله اول جلوگیری کنیم. ما صرفاً این مورد را منع می کنیم که حاوی یک علامت باشد id ویژگی.

type ReservedKeys = {
  id: string;
}

function createItem<TItem extends object>(
  item: TItem extends ReservedKeys ? never : TItem
): TItem {
  if('id' in item) throw new Error("Item must not contain an ID");
  // Database sets ID
  const newItem = db.insert(item);

  return newItem;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در این مثال ما a را تعریف می کنیم ReservedKeys با کلیدهای ممنوعه تایپ کنید اینها خصوصیاتی هستند که نباید برای کالا مجاز باشند. در امضای تابع، از آن استفاده می کنیم TItem extends ReservedKeys برای بررسی اینکه آیا عمومی است TItem زیر مجموعه ای از ReservedKeys. اگر اینطور باشد، نوع عنصر را روی مقدار ویژه قرار می دهیم never.

بیایید به مثال قبلی خود برگردیم. حالا وقتی یک شی با ID مشخص می کنیم چه اتفاقی می افتد؟

// What will happen?
//> TypeScript error: Argument of type '{ id: string; name: string; email: string; }' is not assignable to parameter of type 'never'
const user = createItem({ id: "0d92b425efc9" name: "John", email: "[email protected]" });
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

TypeScript خطایی را گزارش می دهد که شیئی که به تابع ارسال کرده ایم با نوع مورد انتظار مطابقت ندارد.

زمین بازی TypeScript

زمین بازی TypeScript

البته، هرگز نباید برای جلوگیری از چنین خطاهایی به بررسی نوع استاتیک به تنهایی تکیه کنیم. بررسی ملک id در زمان اجرا در پیاده سازی باید همیشه حضور داشته باشید. نوع نفی یک قند نحوی است تا خطاهای احتمالی را در زمان کامپایل پیدا کند و یک امضای تابعی داشته باشد که با اجرا مطابقت داشته باشد.


امیدوارم این پست برای شما مفید بوده باشد. اگر سوال یا نظری دارید، در زیر آن را مطرح کنید. اگر می خواهید با من ارتباط برقرار کنید، می توانید من را در لینکدین یا گیت هاب پیدا کنید. با تشکر برای خواندن!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا