reactjs - كيف يمكنني تقييد نوع React Children في TypeScript، باستخدام الدعم الجديد المُضاف في TypeScript 2.3؟
أحاول الاستفادة من الدعم المضاف مؤخرًا لكتابة أنواع الأطفال في مترجم TypeScript و@types/react، لكنني أواجه صعوبة. أنا أستخدم TypeScript الإصدار 2.3.4.
قل أن لدي شفرة مثل هذه:
interface TabbedViewProps {children?: Tab[]}
export class TabbedView extends React.Component<TabbedViewProps, undefined> {
render(): JSX.Element {
return <div>TabbedView</div>;
}
}
interface TabProps {name: string}
export class Tab extends React.Component<TabProps, undefined> {
render(): JSX.Element {
return <div>Tab</div>
}
}
عندما أحاول استخدام هذه المكونات على هذا النحو:
return <TabbedView>
<Tab name="Creatures">
<div>Creatures!</div>
</Tab>
<Tab name="Combat">
<div>Combat!</div>
</Tab>
</TabbedView>;
أتلقى خطأً كما يلي:
ERROR in ./src/typescript/PlayerView.tsx
(27,12): error TS2322: Type '{ children: Element[]; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<TabbedView> & Readonly<{ children?: ReactNode; }> ...'.
Type '{ children: Element[]; }' is not assignable to type 'Readonly<TabbedViewProps>'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type 'Tab[] | undefined'.
Type 'Element[]' is not assignable to type 'Tab[]'.
Type 'Element' is not assignable to type 'Tab'.
Property 'render' is missing in type 'Element'.
يبدو أنه يستنتج نوع الأطفال على أنه مجرد Element[] بدلاً من Tab[] على الرغم من أن هذا هو النوع الوحيد من الأطفال الذي أستخدمه.
تحديث: سيكون من المقبول أيضًا تقييد واجهة خصائص الأطفال بدلاً من تقييد نوع مكونات الأطفال مباشرة، حيث أن كل ما أحتاج إليه هو استخراج بعض الخصائص المحددة من مكونات الأطفال.
الإجابة رقم 1
تعديل 2: اتضح أن هذه الطريقة تمنع التحذير، ولكن وفقاً للتعليقات، لم يتم التحقق من TabProps بشكل صحيح.
يجب أن تحاول تعيين أبناء الواجهة TabbedViewProps على هذا النحو
interface TabbedViewProps { children?: React.ReactElement<TabProps>[] }
الفكرة هنا ليست أن تخبر TabbedView أن لديها مصفوفة من Tab، بل بدلاً من ذلك أخبر TabbedView أنها تمتلك مصفوفة من element التي تأخذ خصائص معينة. في حالتك TabProps.
تعديل (شكرًا لماتي):
interface TabbedViewProps {
children?: React.ReactElement<TabProps>[] | React.ReactElement<TabProps>
}
الإجابة رقم 2
كما أشار سابقًا، إعلان TabbedView.children كالتالي:
children: React.ReactElement<TabProps> | React.ReactElement<TabProps>[];
سيؤدي ذلك إلى التخلص من الخطأ، لكنه لن يقوم بالتحقق من نوع العناصر الفرعية بشكل صحيح. أي أنه لا يزال بإمكانك تمرير عناصر فرعية غير TabProps إلى TabbedView دون الحصول على أي خطأ، لذا سيكون هذا أيضًا صالحًا:
return (
<TabbedView>
<Tab name="Creatures">
<div>Creatures!</div>
</Tab>
<Tab name="Combat">
<div>Combat!</div>
</Tab>
<NotTabButValidToo />
</TabbedView>
);
ما يمكنك فعله بدلاً من ذلك هو إعلان خاصية، لنقل tabs: TabProps[]، لتمرير الخصائص التي تحتاجها لإنشاء تلك Tab بدلاً من JSX الخاص بها، وعرضها داخل TabbedView:
interface TabbedViewProps {
children?: never;
tabs?: TabProps[];
}
...
const TabbedView: React.FC<TabbedViewProps> = ({ tabs }) => {
return (
...
{ tabs.map(tab => <Tab key={ ... } { ...tab } />) }
...
);
};
