我正在使用一个私人公司的Accordion库。我使用的是TS 4.6.4和React 17。根据文档,如果有多个子节点,它会工作:
question
answer
question
answer
question
answer
但是我得到错误:
This JSX tag's 'children' prop expects a single child of type 'ReactChild | undefined', but multiple children were provided.
这个错误显示在:
<StyledAccordion onChange={onChange}>
<dt>Question(SBTi)?</dt>
<div>answer </div>
<dt>Question(SBTi)?</dt>
<div>answer </div>
StyledAccordion是一个样式化组件:
export const StyledAccordion = styled(Accordion)``
该组件的接口包括:
export interface AccordionProps {
....
....
children?: ReactChild;
....
....
因此,我试图扩展这个接口,使它通过TypeScript支持多个子接口…我认为这里的打字文稿不够完善……
我正在尝试这样做:
interface MultipleChildrenAccordion extends AccordionProps {
children?: React.ReactChild[]|React.ReactNode|undefined;
}
然而我得到:
Interface 'MultipleChildrenAccordion' incorrectly extends interface 'AccordionProps'.
Types of property 'children' are incompatible.
Type 'ReactChild[] | ReactNode' is not assignable to type 'ReactChild | undefined'.
Type 'null' is not assignable to type 'ReactChild | undefined'.ts(2430)
如果你能帮助它接受多个孩子,我将非常感激……
提前谢谢你
编辑:我用
更新了类型type MultipleChildrenAccordion = Omit<AccordionProps, 'children'> & {
children?: React.ReactChild[]|React.ReactNode|undefined;
}
但是现在在<StyledAccordion onChange={onChange}>
上我得到:
No overload matches this call.
Overload 1 of 2, '(props: { onChange?: ((accordion: AccordionAPI, openItems: number[]) => void) | undefined; ref?: Ref<AccordionAPI> | undefined; key?: Key | null | undefined; ... 8 more ...; iconProps?: IconProps | undefined; } & { ...; } & { ...; }): ReactElement<...>', gave the following error.
Type '{ children: Element[]; onChange: (() => void) | undefined; }' is not assignable to type '{ onChange?: ((accordion: AccordionAPI, openItems: number[]) => void) | undefined; ref?: Ref<AccordionAPI> | undefined; key?: Key | null | undefined; ... 8 more ...; iconProps?: IconProps | undefined; }'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type '(ReactChild & (string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal | ReactChild[] | null)) | undefined'.
Type 'Element[]' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>> & ReactChild[]'.
Type 'Element[]' is missing the following properties from type 'ReactElement<any, string | JSXElementConstructor<any>>': type, props, key
Overload 2 of 2, '(props: StyledComponentPropsWithAs<ForwardRefExoticComponent<AccordionProps & RefAttributes<AccordionAPI>>, any, Omit<AccordionProps, "children"> & { ...; }, never, ForwardRefExoticComponent<...>, ForwardRefExoticComponent<...>>): ReactElement<...>', gave the following error.
Type '{ children: Element[]; onChange: (() => void) | undefined; }' is not assignable to type '{ onChange?: ((accordion: AccordionAPI, openItems: number[]) => void) | undefined; ref?: Ref<AccordionAPI> | undefined; key?: Key | null | undefined; ... 8 more ...; iconProps?: IconProps | undefined; }'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type '(ReactChild & (string | number | boolean | ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal | ReactChild[] | null)) | undefined'.
当你扩展一个类型时,你只能使它变窄,而不能变宽。如果允许将它变宽,这基本上会破坏子类型。考虑这个例子:
interface Person {
name: string;
}
const someFunction = (person: Person) => {
console.log(person.name.toUpperCase()); // Should be just fine: name is a string, strings have a toUpperCase property
}
const example: Person = {
name: 'bob'
}
someFunction(example);
现在我想从人扩展。Typescript将允许我将其缩小,例如将名称限制为特定的字符串。这个扩展的类型可以传递给someFunction, someFunction仍然可以工作:
interface SpecificPerson extends Person {
name: 'bob' | 'alice' | 'eve',
}
const example2: SpecificPerson = {
name: 'alice'
}
someFunction(example2);
但是如果我被允许让事情变得更广泛,那么someFunction就会中断。name不再是字符串,所以当someFunction尝试调用.toUpperCase()
时,将抛出一个异常
interface Entity extends Person {
name: string | number; // Typescript won't actually let me do this
}
const example3: Entity = {
name: 42,
}
someFunction(example3); // This shows a typescript error at compile time, and would throw a runtime error if it was allowed.
操场上联系
如果你想要一个类似于AccordionProps的类型,但它将子类型替换为更宽的类型,你可以这样做,但它不会从AccordionProps扩展。你将不能在期望AccordionProps:
的地方使用它type MultipleChildrenAccordionProps = Omit<AccordionProps, 'children'> & {
children?: React.ReactChild[]|React.ReactNode|undefined;
}
注意Accordion不能使用这个类型。如果accordion被实现为只支持单个子节点,那么你必须给它一个单独的子节点。
根据Accordion是如何实现的,也许你可以给它传递一个片段:
<StyledAccordion onChange={onChange}>
<>
<dt>Question(SBTi)?</dt>
<div>answer </div>
<dt>Question(SBTi)?</dt>
<div>answer </div>
</>
</StyledAccordion>
如果不行,给它一个div:
<StyledAccordion onChange={onChange}>
<div>
<dt>Question(SBTi)?</dt>
<div>answer </div>
<dt>Question(SBTi)?</dt>
<div>answer </div>
</div>
</StyledAccordion>