استنباط نوعهای اتحادیه با گاردهای نوع در تایپاسکریپت
به نظر میرسد TypeScript در استنتاج نوعهای اتحاد (union types) برای محافظهای نوع (type guards) مشکل دارد. به عنوان مثال، یک تابع برای ترکیب آرایهای از محافظهای نوع را در نظر بگیرید که دارای امضای زیر است
function combine<T>(guards: ((x: any) => x is T)[]): (x: any) => x is T
و به نگهبانان نوع زیر با A و B که خواص متفاوتی دارند، توجه کنید
function isA(x: any): x is A
function isB(x: any): x is B
حالا من انتظار دارم که combine([isA, isB]) کار کند و نوع استنباط شده آن (x: any) => x is A | B باشد، اما در عوض خطایی دریافت میکنم که میگوید یک آرگومان با نوع ((x: any) => x is A | (x: any) => x is B)[] قابل انتساب به پارامتر با نوع (x: any) => x is A نیست، به این معنا که T به عنوان A استنباط میشود نه A | B.
هنگام مشخص کردن T به صورت صریح، یعنی combine<A|B>([isA, isB])، همانطور که انتظار میرود کار میکند. آیا راهی وجود دارد که امضای combine را تغییر داد تا این موضوع قابل استنتاج باشد؟
پاسخ شماره ۱
شما میتوانید از یک پارامتر نوع برای نشان دادن کل تابع بهجای تنها نوع محافظتشده استفاده کنید. این به کامپایلر اجازه میدهد تا یک اتحاد از توابع محافظتکننده را استنتاج کند. سپس میتوانیم از یک نوع شرطی برای استخراج اتحاد از نوعهای محافظتشده استفاده کنیم:
type GuardType<T> = T extends (o: any) => o is infer U ? U : never
class A { q: any }
class B { p: any }
declare function isA(x: any): x is A
declare function isB(x: any): x is B
declare function combine<T extends ((x: any) => x is any)>(guards: T[]): (x: any) => x is GuardType<T>
let isAB = combine([isA, isB]); // (x:any) => x is A|B
