typescript - 'T' میتواند با یک نوع دلخواه نمونهسازی شود که ممکن است با 'T | null | undefined' نامرتبط باشد
تعدادی از این سوالات در SO وجود دارد، اما هنوز به نظر میرسد هیچ کدام به من کمک نمیکند که بفهمم اینجا چه خبر است.
در این زمینه، من از Pinia (VueJS) استفاده میکنم و در حال ایجاد یک فروشگاه «سراسری» هستم، برای مجموعهای از اقدامات/حالتهای مشترک که در بسیاری از ماژولها وجود دارند.
import find from 'lodash/find';
export interface IGenericPaginationStore<T> {
list: T[];
count: number;
page: number;
next: string | null;
previous: string | null;
active: T | null;
pageSize: number;
}
// store.ts
setActive<T extends { uuid: string }>(state: IGenericPaginationStore<T>, args: { uuid?: string | null, resource?: T | null }) {
if (args.resource) {
state.active = args.resource
state.list.forEach((resource: T, index) => {
if (resource?.uuid === args.resource?.uuid) {
state.list[index] = args.resource // **** ERROR 1 HERE ****
}
})
return;
}
},
خطا ۱:
TS2322: Type 'T | null | undefined' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'T | null | undefined'.
من واقعاً نمیتوانم بفهمم چرا این کار نمیکند. هر کمکی بسیار قدردانی خواهد شد.
پاسخ شماره ۱
مشکل شما این است که اثرات بررسی args.resource برای صحت، در محدوده بدنه callback تابع forEach() باقی نمیماند. این یک محدودیت کلی در تحلیل جریان کنترل TypeScript است؛ اساساً نمیتواند مرزهای تابع را بپیماید. برای بحث کامل درباره اینکه چرا این مشکل سختی است و چرا رفتار به این شکل است، به microsoft/TypeScript#9998 مراجعه کنید. به طور خلاصه، کامپایلر نمیتواند به سادگی اطمینان حاصل کند که args.resource قبل از فراخوانی callback تابع forEach() دوباره اختصاص داده نمیشود. ما میدانیم که forEach() فوراً اجرا خواهد شد، اما کامپایلر نمیتواند این را بداند. (برای درخواست ویژگی جهت اجازه دادن به ابراز اینکه یک callback فوراً اجرا خواهد شد، به microsoft/TypeScript#11498 مراجعه کنید.)
بنابراین، باریک شدن args.resource از T | undefined | null به T در داخل کالبک لغو میشود. و کامپایلر شکایت میکند که نمیتوانید مقداری از نوع T | undefined | null را به یک ویژگی از نوع T اختصاص دهید.
در مواردی مانند این، راه حل معمول ایجاد یک const جدید با مقداری است که میcخواهید تایپ کنید. یک const را نمی توان دوباره اختصاص داد و کامپایلر این را می داند. بنابراین اگر بررسی کنید که یک const برابر با null یا undefined نیست، آن const نمیcتواند در هیچ محدودهcای، حتی در برخی از تماسcهای برگشتی، null یا تعریف نشده باشد:
const resource = args.resource; // copy the value here
if (resource) {
// resource is T here
state.active = resource
state.list.forEach((r: T, index) => {
// resource is still T here
if (r.uuid === resource.uuid) {
state.list[index] = resource; // okay
}
})
return;
}
حال کامپایلر خوشحال است، زیرا resource داخل callback به عنوان نوع T دیده میشود و بنابراین میتواند به ویژگیای از نوع T نیز اختصاص یابد.
لینک زمین بازی به کد
