Почему эта ошибка?
Есть две причины, почему вы получаете эту странную ошибку:
- Тип
React.FC
уже включает тип по умолчанию children
, тип ReactNode
. ReactNode
- очень слабый тип , которого вам, вероятно, следует избегать в пользу более сильных типов.
Прежде всего, вот встроенные типы React:
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactNodeArray extends Array<ReactNode> {}
type ReactFragment = {} | ReactNodeArray;
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
type PropsWithChildren<P> = P & { children?: ReactNode };
1.) Вы используете FC<Props>
для ввода Comp
. FC
внутренне уже включает объявление children
, набранное как ReactNode
, которое объединяется с вашим определением children
из Props
:
type Props = { children: ((x: number) => ReactNode) | ReactNode } & { children?: ReactNode }
// this is how the actual/effective props rather look like
2 .) Если вы посмотрите на тип ReactNode
, вы увидите, что типы становятся значительно более сложными. Еще хуже: ReactNode
включает тип {}
через ReactFragment
, , который является супертипом всего, кроме null и undefined ! (Я не знаю, почему им, видимо, пришлось go этот маршрут; возможно эта проблема улучшает набор текста).
Как следствие, вы делаете ваш children
тип намного шире как необходимо. Это также причина, по которой вы получаете эту ошибку - охранник типа typeof props.children === function"
не может больше сузить ваш тип ошибки до function
.
Решение
В дополнение к вашему решению вы можете полностью опустить тип FC<Props>
. Это просто особая функция в конце концов, чьи реквизиты вкл. children
вы хотите, чтобы пользовательский тип все равно. Это приведет к более сильным и простым типам для отображения компилятора и IDE. Если я возьму ваше определение Anything that can be rendered
для children
, это может быть:
import React, { ReactChild, ReactPortal } from "react";
type Children = ReactChild | Array<Children> | ReactPortal
type Props = {
children: ((x: number) => Children) | Children;
};
const Comp = (props: Props) => {...}
Вы могли бы даже определить свою собственную версию FC
, которая имеет все от React.FC
, за исключением тех широких children
types:
type FC_NoChildren<P = {}> = { [K in keyof FC]: FC[K] } & // propTypes etc.
{ (props: P, context?: any): ReactElement | null } // call signature
const Comp: FC_NoChildren<Props> = props => {...}
PS: я не упомянул Comp.propTypes
- ИМО, вы можете лучше использовать безопасность времени компиляции с TS.
Надеюсь, что это имеет смысл для вас, ура!