تایپ empty object، یعنی {}
در تایپ اسکریپت به شکلی که ما انتظار داریم رفتار نمیکند. یعنی به جای نمایش یک آبجکت خالی، هر مقداری را نشان میدهد به جز مقادیر null
و undefined
.
دلیل این اتفاق این است که سیستم تایپ در تایپ اسکریپت به شکل structural است، نه nominal. بنابراین همه چیز به جز null
و undefined
یک آبجکت هستند. در نتیجه هر چیزی را میتوانیم به یک آبجکت خالی نسبت دهیم.
اگر میخواهیم یک شی خالی را نشان دهیم، میتوانیم به جای آن از Record<string, never>
استفاده کنیم.
تایپ empty object در تایپ اسکریپت واقعاً آنطور که انتظار داریم رفتار نمیکند. یعنی این که نشان دهنده any object نیست. در عوض، هر مقداری که null
یا undefined
نباشد را ارائه میدهد:
const example1: {} = "str"; const example2: {} = 123; const example3: {} = true; const example4: {} = { foo: "whatever", };
در این مثال، ما example1
را به عنوان یک آبجکت خالی ایجاد میکنیم، اما میتوانیم یک رشته را به آن ارسال کنیم. همچنین میتوانیم یک عدد به آن بفرستیم. علاوه بر این می توانیم یک Boolean و یا هر آبجکت دیگری را به آن ارسال نماییم.
تنها چیزهایی که نمیتوانیم به آن ارسال کنیم مقادیر null
یا undefined
است:
const example5: {} = null; Type 'null' is not assignable to type '{}'. const example6: {} = undefined; Type 'undefined' is not assignable to type '{}'.
اگر از ESLint استفاده میکنیم، حتی ممکن است با خطا زیر مواجه شویم:
Don't use {} as a type. {} actually means "any non-nullish value".
در این مقاله به شکل دقیق بررسی میکنیم که چرا این توصیه خوب است.
این موضوع همچنین با تایپ Object
نیز اتفاق میافتد، که به نظر میرسد فقط یک نام مستعار برای {}
میباشد:
const obj1: Object = "str"; const obj2: Object = null; Type 'null' is not assignable to type 'Object'.
بنابراین این دقیقاً به همان شیوه رفتار میکند. در نتیجه ما نیز نباید از این تایپ Object
استفاده کنیم.
اگر بخواهیم نوعی آبجکت خالی را نشان دهیم، میتوانیم از Record<PropertyKey, never>
استفاده کنیم.
type EmptyObj = Record<PropertyKey, never>; const emptyObj1: EmptyObj = {}; const emptyObj2: EmptyObj = { foo: "whatever", Type 'string' is not assignable to type 'never'. }; const emptyObj3: EmptyObj = "str"; Type 'string' is not assignable to type 'EmptyObj'. const emptyObj4: EmptyObj = 123; Type 'number' is not assignable to type 'EmptyObj'.
کاری که این کد کار انجام میدهد این است که میتوانیم یک آبجکت خالی را ارسال کنیم. این کار، ما را از ارسال هر چیزی که property روی آن است باز میدارد. همچنین از ارسال موارد primitive یا null و یا undefined نیز جلوگیری میکند.
این مفهوم تنها زمانی ممکن است مفید باشد که بخواهیم یک محدودیت واقعاً گسترده برای یک تابع داشته باشیم. فرض کنید میخواهیم مطمئن شویم چیزی که به تابع ارسال میکنیم، null
یا undefined
نیست:
const myFunc = (constraint: {}) => {}; myFunc("str"); myFunc(123); myFunc(true);
اما حتی در این شرایط، نمیتوانیم به هیچ ویژگی در constraint
دسترسی داشته باشیم:
const myFunc = (constraint: {}) => { constraint.foo; Property 'foo' does not exist on type '{}'. };
با این خطا مواجه میشویم:
Property 'foo' does not exist on type ''.
این اتفاق میافتد زیرا ما در حال تلاش برای دسترسی به یک ویژگی در یک آبجکت خالی هستیم. بنابراین کار زیاد مفیدی نیست.
تنها جایی که این کار میتواند مفید باشد، یا حداقل جایی که میخواهیم در بخش به آن بپردازیم، به عنوان یک محدودیت در یک تابع generic است.
const myGenericFunc = <T extends {}>(t: T) => { return t; }; const result1 = myGenericFunc("str"); const result2 = myGenericFunc(123); const result3 = myGenericFunc(true);
داخل تایع myGenericFunc
، میخواهیم مطمئن شویم که نمیتوانیم null
یا undefined
را به تابع generic ارسال کنیم. اگر ماوس را روی myGenericFunc
نگه داریم، میبینیم که str
را میگیرد و آن را در نتایج return میکند.
اما زمانی که سعی میکنیم به صورت null یا undefined ارسال کنیم، با خطا مواجه میشویم.
const result4 = myGenericFunc(null); Argument of type 'null' is not assignable to parameter of type '{}'. const result5 = myGenericFunc(undefined); Argument of type 'undefined' is not assignable to parameter of type '{}'.
با توجه به مفاهیمی که در این مقاله با آنها آشنا شدیم، ما نباید در هیچ بخشی از تایپ {}
استفاده کنیم. زیرا یک قانون linting پیدا کردیم که ما را از استفاده از آن باز میدارد. به همین دلیل است که این تایپ، چیزی که ما فکر میکنیم را نشان نمیدهد، اما گاهی اوقات برای محدود کردن genericها مفید میباشد.