ReactJS - تایپاسکریپت جنریک مختلف در آرایهای از اینترفیس
من یک نوع با یک نوع عمومی دارم تا برخی گزینههای اضافی برای یک کامپوننت تابع تعریف کنم.
type FCWithOptions<T> = React.FC<{options?: T}>;با استفاده از این نوع، من برخی مؤلفهها را با خصوصیات اضافی خودشان تعریف میکنم
interface ComponentAOptions {
option1: string;
option2: number;
}
interface ComponentBOptions {
prop1: boolean;
prop2: Record<string, string>;
}
type ComponentAFC = FCWithOptions<ComponentAOptions>
type ComponentBFC = FCWithOptions<ComponentBOptions>
const ComponentA: ComponentAFC = ({options}) => {
return <>Component A</>
}
const ComponentB: ComponentBFC = ({options}) => {
return <>Component B</>
}
پس چیزی که من نیاز دارم این است که این کامپوننتها را در یک کامپوننت ظرف با استفاده از یک آرایه از رابطها منتقل کنم که شامل کامپوننتی است که باید منتقل شود و گزینههای سفارشی آن کامپوننت از طریق یک ویژگی.
interface ComponentValue<T>{
component: FCWithOptions<T>;
componentOptions?: T;
}
interface MainComponentProps<C>{
components: ComponentValue<C>[]
}
function MainComponent<C>({}: MainComponentProps<C>) {
return <>Main</>
}
کاری که باید بتوانم انجام دهم چیزی شبیه به این است:
<MainComponent components={[
{component: ComponentA, componentOptions: {option1: "", option2: 2}},
{component: ComponentB, componentOptions: { prop1: true, props: {} }}
]} />
اما این فقط برای اولین عنصر آرایه کار میکند، اگر عناصر دیگری اضافه کنم، چند تایپاسکریپت اعتبارسنجی دریافت میکنم
چطور میتوانم این را محقق کنم؟ ممنون
اینجا یک زمین بازی است
پاسخ شماره ۱
اگر شما یک نوع عمومی F<T> داشته باشید و نیاز داشته باشید یک آرایه از مقادیر آن نوع را نشان دهید که هر عنصر از آرایه انتخاب متفاوتی از T داشته باشد، یعنی اگر شما نیاز به یک نوع تاپل مانند [F<T0>, F<T1>, F<T2>, ⋯ , F<TN>] داشته باشید، بهترین روش احتمالاً استفاده از یک نوع تاپل/آرایه نگاشتهشده بر روی یک تاپل از فقط انواع T0، T1 و غیره است. یعنی اگر شما نوع type T=[T0, T1, T2, ⋯, TN] را داشته باشید، سپس میتوانید type MapF<T>={[I in keyof T]: F<T[I]>} را به آن اعمال کنید تا [F<T0>, F<T1>, F<T2>, ⋯ , F<TN>] را بدست آورید.
این به این معناست که باید کد شما را طوری تغییر دهیم که شبیه این شود:
interface MainComponentProps<C extends any[]> {
components: [...{ [I in keyof C]: ComponentValue<C[I]> }]
}
function MainComponent<C extends any[]>({ }: MainComponentProps<C>) {
return <>Main</>
}
(جایی که ما از C به جای T و از ComponentValue<⋯> به جای F<⋯> استفاده میکنیم.) تنها تفاوت این است که من نوع components را با یک نوع تاپل واریادیک ([...⋯]) محصور کردهام تا به کامپایلر نشانه دهم که میخواهیم یک تاپل استنتاج شود و نه یک آرایه بدون ترتیب با طول دلخواه وقتی MainComponent فراخوانی میشود. (این استفاده از نوعهای تاپل واریادیک در ms/TS#39094 توضیح داده شده است، "نوع [...T]، جایی که T یک پارامتر نوع شبیه آرایه است، میتواند به طور مناسب برای نشان دادن ترجیح برای استنتاج نوع تاپل استفاده شود").
بیایید آن را امتحان کنیم:
<MainComponent components={[
{ component: ComponentA, componentOptions: { option1: "", option2: 2 } },
{ component: ComponentB, componentOptions: { prop1: true, prop2: {} } }
]} />
// MainComponentProps<[{ option1: string; option2: number; }, { prop1: boolean; prop2: {}; }]>
خوب به نظر میرسد. نوع C به عنوان [{ option1: string; option2: number; }, { prop1: boolean; prop2: {}; }] استنباط میشود و بنابراین نوع نگاشتشده [...{ [I in keyof C]: ComponentValue<C[I]> }] با نوع ویژگی components مطابقت دارد.
لینک زمین بازی به کد
