تایپاسکریپت: محدود کردن نوع: تأیید عدم تعریف و در نتیجه حذف از نوع


هر دو این خطوط با خطای «Object possibly undefined» در _e[k] مواجه میشوند:

obj[k] = typeof _e[k] === "undefined" ? "" : _e[k].toString();
obj[k] = _e[k] === undefined ? "" : _e[k].toString();

کد _e[k] یک اتحاد از انواع مختلف است، بنابراین اعمال تبدیل نوع دستی قابل استفاده نیست. چگونه میتوانم از این خطا خلاص شوم؟

بهروزرسانی: بنابراین به صورت کلیتر، سوال من میتواند اینگونه بیان شود: آیا راهی وجود دارد که نوع یک متغیر را با بررسی در برابر نوعهای خاصی که باید مستثنی شوند محدود کنیم؟

مثال حداقلی:

class test {
    a!: string;
    b?: number;
}
const t: test = { a: "hi", b: 2 };
for (const k of Object.keys(t) as Array<keyof test>) {
    console.log(t[k] == undefined ? "LOL" : t[k].toString());
}

پاسخ شماره ۱

یک باگ/مسئله طولانیمدت وجود دارد که TypeScript تحلیل جریان کنترل را برای محدود کردن نوع یک ویژگی انجام نمیدهد اگر کلید ویژگی یک متغیر باشد: microsoft/TypeScript#10530؛ این موضوع حل نشد زیرا رفع آن باعث کاهش شدید عملکرد میشد. در مورد شما، این بدان معناست که بررسیهای نوع حفاظتی روی _e[k] بر استفادههای بعدی از _e[k] تأثیری نخواهد داشت.

راه حل پیشنهادی من برای این، اختصاص دادن ویژگی دسترسی با اندیس به یک متغیر جدید و بررسی آن است:

const ek = _e[k]; // new variable
obj[k] = typeof ek === "undefined" ? "" : ek.toString(); // no error now

متغیر جدید ek آنالیز نوع جریان کنترل عادی را دریافت میکند، و محافظ نوع شما کار میکند.

امکانات دیگر برای کاربردهای مختلف:

  • اگر شما قبلاً در برابر undefined و null بررسی کردهاید اما کامپایلر نمیتواند آن را تشخیص دهد، سادهترین تغییر، استفاده از عملگر تأیید غیر تهی ! است:

    obj[k] = typeof _e[k] === "undefined" ? "" : _e[k]!.toString(); // non-null assertion
    
  • شما میتوانید کد حذف نوع خود را به یک عبارت مستقل و خودکفا بازسازی کنید تا هرگز نیازی به بررسی مجدد مقدار اصلی نداشته باشید. به عنوان مثال:

    obj[k] = (_e[k] || "").toString(); // refactor
    

    آن کد خاص فقط کار میکند و تنها مقادیر نادرست که _e[k] میتواند داشته باشد undefined و "" هستند. اگر _e[k] میتوانست 0 باشد، آن نتیجه متفاوتی میداد. به طور کلی میتوانید یک تابع جدید بسازید تا هر کاری که میخواهید انجام دهد:

    function defined<T, U>(x: T | undefined, dflt: U): T | U {
        return typeof x !== "undefined" ? x : dflt;
    }
    obj[k] = defined(_e[k], "").toString(); // refactor 2
    

باشه، امیدوارم یکی از اینها کمک کند؛ موفق باشی!

لینک زمین بازی به کد

پاسخ شماره ۲

پس، یک راهحل (نسبتاً موقتی) که برای مورد استفاده من مناسب است (اما در بسیاری از سناریوهای دیگر مناسب نخواهد بود) این است:

obj[k] = _e[k] === undefined ? "" : String(_e[k]);

هنوز علاقهمند به پیشنهادهای (بهتر) هستم که در حالت عمومیتر کار کنند (به بهروزرسانی سؤال مراجعه کنید)