typescript - آیا روشی وجود دارد که بتوانم نوع بازگشتی تابع ژنراتور را دریافت کنم؟
من میخواهم نوع بازگشتی تابع ژنراتور را بدست آورم.
برای مثال
function* test(){
yield 'a';
yield 123;
return true;
}
// what I'm trying to get
type A = GetGeneratorReturn<test>; // -> A has type boolean
جایی که اکنون هستم.
type B = ReturnType<ReturnType<typeof test>['next']>['value'];
// B has type `true | "a" | 123`
(من فکر کردم اگر اولین آیتم از نوع Union B را بگیرم، میتوانم نوع بازگشتی را به دست آورم)
پاسخ شماره ۱
یک مسئله باز وجود دارد که درباره این مشکل در کنار مسائل دیگر صحبت میکند، اما این مسئله نسبتاً قدیمی است و به نظر نمیرسد کسی به آن رسیدگی کند، زیرا برخی از مسائل دیگر حل شدهاند. من اخیراً اشارههایی به آن در اینجا و آنجا دیدهام. مرتبطترین مسئله موجود به نظر میرسد همین مورد باشد. اگر این برای شما اهمیت دارد، ممکن است بخواهید به گیتهاب مراجعه کرده و به این مسائل 👍 بدهید.
فعلاً به نظر میرسد که تایپهای ژنراتور در تایپاسکریپت تنها به شما دسترسی به اتحاد غیرتفکیکشدهای از نوعهای yield و نوع return میدهند. و متأسفانه، نمیتوانید به ترتیب یک نوع اتحاد تکیه کنید. این یک جزئیات پیادهسازی کامپایلر است؛ از آنجا که X | Y معادل Y | X است، کامپایلر آزاد است که یکی را به دیگری تغییر دهد. و گاهی هم این کار را انجام میدهد:
function* test() {
yield 'a';
yield 123;
return true;
} // function test(): IterableIterator<true | "a" | 123>
function* oops() {
yield true;
yield 123;
return 'a'
} // function oops(): IterableIterator<true | "a" | 123>
نوع بازگشتی oops() دقیقاً همان نوع بازگشتی test() است. این بدان معناست که ایده شما برای استخراج عنصر اول/آخر یک اتحادیه امکانپذیر نیست.
ممکن است راهی وجود داشته باشد که کمک کند، به ویژه اگر بتوانید با تعریف ژنراتور بازی کنید و مشکلی با وجود برخی نوعهای شبحی نداشته باشید:
type Returnable<T> = { __returnedType?: T } & T
const ret = <T>(t: T) => t as Returnable<T>;
type GeneratorReturn<T extends (...args: any) => IterableIterator<any>> =
ReturnType<T> extends IterableIterator<infer I> ?
NonNullable<Extract<I, Returnable<unknown>>['__returnedType']> : never
function* test() {
yield 'a';
yield 123;
return ret(true); // only use ret() here
}
function* oops() {
yield true;
yield 123;
return ret('a'); // only use ret() here
}
type TestRet = GeneratorReturn<typeof test>; // true
type OopsRet = GeneratorReturn<typeof oops>; // "a"
که تا حدی کار میکند، اما ممکن است چیزی نباشد که بخواهید دنبال کنید. خب، متأسفم که نمیتوانم جواب بهتری پیدا کنم. موفق باشید!
پاسخ شماره ۲
شما اکنون میتوانید به این شکل عمل کنید:
type GeneratorReturnType<T extends Generator> = T extends Generator<any, infer R, any> ? R: never;
type TestType = GeneratorReturnType<ReturnType<typeof test>>; // bool
زمین بازی
