استنتاج پیشرفته تایپاسکریپت از یک ساختار شیء به ساختار شیء دیگر
سناریو
من یک شیء دارم که برخی تنظیمات برای دادههایی که نیاز به حل شدن دارند را تعریف میکند. این شیء شامل کلاسها و نامهای رشتهای متدهایی است که در آن کلاسها وجود دارند.
{
orders: {
service: OrderService, // The class
serviceMethod: 'getOrders' // The method name which exists on the class
},
cart: {
service: OrderService,
serviceMethod: 'getCart'
}
}
کلاس اینطور به نظر میرسد
export class OrderService {
public getOrders = (): Observable<Order[]> = {
return of([ {id: '1', name: 'Order 1' ])
};
public getCart = (): Observable<Cart> => {
return of({ products: [] })
};
}
پس از اجرای پیکربندی، دادههای حلشده به این شکل به نظر میرسند:
{
orders: [ {id: '1', name: 'Order 1' ], // Data of type Order[]
cart: { products: [] } // Data of type Cart
}
مسئله
من سعی دارم به طور خودکار نوع دادههای حل شده را بر اساس پیکربندی رزولور استنباط کنم. من این نوع را دارم، اما با اینکه T[P]['serviceMethod'] extends keyof T[P]['service'] باید اطمینان دهد که T[P]['serviceMethod'] یک کلید از کلاس ارائه شده است، این مورد شناخته نمیشود
در اینجا یک StackBlitz از مشکل وجود دارد https://stackblitz.com/edit/stackblitz-starters-9yqbuq?file=src%2Fapp%2Fapp.interface.ts
اگر کسی بتواند این را درست کند، من واقعا بسیار سپاسگزار خواهم بود :)
export interface ResolverResource<TService = any> {
service: Type<TService>;
serviceMethod: keyof TService;
}
export type ResolvedData<T, TService = any> = {
// Check if T[P] is a ResolverResource
[P in keyof T]: T[P] extends ResolverResource<TService>
// Check if T[P]['serviceMethod'] exists on T[P]['service']
? T[P]['serviceMethod'] extends keyof T[P]['service']
// Check if T[P]['service'][T[P]['serviceMethod']] is a function that returns an Observable
// and infer the output type of the Observable
? T[P]['service'][T[P]['serviceMethod']] extends (...args: any[]) => Observable<infer U>
? U
: never
: never // Here is where it fails. It doesn't recognize that T[P]['serviceMethod'] is a key of T[P]['service']
: never;
};
پاسخ شماره ۱
دارم فکر میکنم که محدودیتی در تایپاسکریپت وجود دارد که نمیتواند انواع صریح را از Observable هنگام استفاده از keyof استنتاج کند. مستندات نشان میدهند که همیشه اجتماع تمام کلیدها را خروجی میدهد.
انجام موارد زیر باعث میشود کد شما کامپایل شود اما هر دو ویژگی orders و carts یک اتحاد از یکدیگر خواهند بود.
export type ResolvedData<T, TService = any> = {
[P in keyof T]: T[P] extends ResolverResource<TService>
?
// You were missing this part, as 'keyof' Type<T> doesnt bring back the keys in the generic constraint
T[P]['service'] extends Type<infer U>
?
T[P]['serviceMethod'] extends keyof U
?
U[T[P]['serviceMethod']] extends (
...args: any[]
) => Observable<infer V>
? V
: never
: never
: never
: never;
};
این چیزی شبیه به این به شما میدهد:
const resolvedData: ResolvedData<typeof resourceConfig> = {
orders: [],
cart: { products: [] },
};
// resolvedData.orders == Cart | Order[]
// resolvedData.cart == Cart | Order[]
