@types/react
, и у меня возникли проблемы.Definitions by:
в index.d.ts
), чтобы они могли отвечать.Следующие компоненты
const SFC: React.StatelessComponent = (props) => props.children;
class C extends React.Component {
render() {
return this.props.children;
}
}
дай ошибки
Type '(props: { children?: ReactNode; }) => ReactNode' is not assignable to type 'StatelessComponent<{}>'.
Type 'ReactNode' is not assignable to type 'ReactElement<any> | null'.
Type 'undefined' is not assignable to type 'ReactElement<any> | null'.
Class 'C' incorrectly extends base class 'Component<{}, {}>'.
Types of property 'render' are incompatible.
Type '() => ReactNode' is not assignable to type '() => false | Element | null'.
Type 'ReactNode' is not assignable to type 'false | Element | null'.
Type 'undefined' is not assignable to type 'false | Element | null'.
Это работает, если вы оберните children
в Element
.
Возврат children
довольно распространен при создании компонентов Provider, которые просто добавляют что-то к context
.
Я попробовал следующие исправления для index.d.ts
- render(): JSX.Element | null | false;
+ render(): ReactNode;
- (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
+ (props: P & { children?: ReactNode }, context?: any): ReactNode;
но у меня повсюду были ошибки при попытке lint, которые я не знаю, как исправить.
TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.
Нет, это изменение неверно. В настоящее время вы не можете возвращать несколько элементов в React. Даже если вы делаете это где-то, скорее всего, это как-то инкапсулировано в одном.
Только в React 16 с Fiber это возможно :)
не уверен, изменили ли они поведение реакции, но автор редукции/реакции продемонстрировал возможность вернуть this.props.children для создания тонких оберток (только для добавления childContext к элементам), как показано в https://egghead.io/lessons/ javascript-redux-передача-хранилища-вниз-неявно-через-контекст
Однако react-native позволяет вам возвращать массив элементов JSX из рендеринга. обходной путь заключается в том, чтобы обернуть this.props.children
в React.Children.only(this.props.children)
, и он будет сгенерирован, если в качестве корня имеется более одного элемента.
Правильно, вы можете использовать React.Children.only
, но и ReactNode
, и ReactElement
являются допустимыми значениями this.props.children
.
const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>
является действительным и разумным кодом React.
Вы можете вернуть массив элементов в реакции 16, но TS выдает ошибку, потому что думает, что вы не можете.
Изменить: сделайте это children: JSX.Element[];
, чтобы исправить это
Судя по моему опыту, ReactNode должен работать.
const Id: React.SFC<{}> = (props) => props.children
const App = ()= > <Id>This should work but instead fails</Id>
Есть ли шанс, что это отразится на @types/react
?
Без этого я не могу набирать детей React
В настоящее время я оборачиваю children
в React.Fragment
, чтобы обойти это.
Есть какие-нибудь обновления на нем?
Не уверен, что это более или менее правильно, чем обертывание children
в React.Fragment
, но мне повезло с этим
return (children as React.ReactElement);
return <>{foo(}</>;
всю ночь напролет. <>
— обходной путь.
Это вызывает проблемы и у меня.
У меня есть HOC, который добавляет свойства к данному компоненту, и я пытаюсь использовать его с функциональным компонентом, имеющим return children;
. Это работает, только если я использую обходной путь return <>{children}</>;
.
Вот упрощенная версия HOC:
export interface ExtraProps {
extraProp1: string;
}
export const withExtraProps = <P extends object>(Component: React.ComponentType<P>) => {
return class extends React.Component<Omit<P, keyof ExtraProps>> {
render() {
const extraProps = {
extraProp1: 'test'
};
return (
<Component {...this.props as P} {...extraProps} />
)
}
}
}
Вот упрощенная версия функционального компонента:
interface ComponentProps extends ExtraProps {
children?: React.ReactNode;
loadingComponent?: ReactElement;
}
export function ExampleComponent(props: ComponentProps) {
const { children, loadingComponent } = props;
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
await someAsyncCall();
setLoading(false);
}
fetchData();
});
if (loading) {
return loadingComponent || null;
}
return children;
}
// This line errors:
export const FeatureFlag = withExtraProps(ExampleComponent);
Я получаю следующую ошибку:
Argument of type '(props: ComponentProps) => {} | null | undefined' is not assignable to parameter of type 'ComponentType<ComponentProps>'.
Type '(props: ComponentProps) => {} | null | undefined' is not assignable to type 'FunctionComponent<ComponentProps>'.
Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
Если я добавлю возвращаемый тип ReactElement | null
в ExampleComponent, он перестанет жаловаться на передачу его в HOC, но по-прежнему будут возникать ошибки, когда я возвращаю дочерние элементы:
export function ExampleComponent(props: ComponentProps): ReactElement | null {
...
...
return children; // Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
}
Как и в случае с другими здесь, если я изменю его на return <>{children}</>;
, он сработает, но будет казаться грубым и ненужным.
У меня _точно_ та же проблема, что и у @kyrstenkelly : функция HOC передается React.FC
, которая отображает ее дочерние элементы.
Исправление <> children(...) </>
работает, но есть ли лучшее решение?
Тоже есть такая проблема! В настоящее время мы предлагаем решение для упаковки решения с помощью React.Fragment.
То же самое
interface IIntlMessageProps {
id: string;
valuesGiven?: {[key:string]:string};
}
// this doesn't work - -- TS2769 Type 'null' is not assignable to type '(nodes:ReactNodeARray) => ReactNode' | ... | undefined
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
{props.children}
</FormattedMessage>
)
};
//Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
<React.Fragment>{props.children}</React.Fragment>
</FormattedMessage>
)
};
// Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> | null = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
<>{props.children}</>
</FormattedMessage>
)
};
// Nope -- TS2769 Type '{}' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
return (
<FormattedMessage id={props.id} values={props.valuesGiven}>
{props.children ? props.children : undefined}
</FormattedMessage>
)
};
Кажется, я перепробовал все, что здесь советовали... :( Любая подсказка?
Решение заключается в том, что вам нужно обернуть его фрагментом.
import React from 'react'
const Something: React.FC = ({ children }) => (
<> { children } </>
)
это исправит ошибку Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponent
.
Если возможно, я хотел бы избежать фрагментов и сделать так, чтобы система типов JSX поддерживала те же типы конструкций, что и JavaScript и Flow React, что помогает TypeScript лучше работать с шаблонами сторонних библиотек.
Еще один неидеальный вариант, который я нахожу, заключается в том, что фрагменты углубляют дерево компонентов, особенно в компонентах-утилитах/обертках (пример: реакция-заполнитель). Приведение к React.ReactElement
кажется лучшим подходом в такого рода библиотеках, но я бы предпочел не приводить.
Я попробовал подход к изменению этого типа, но застрял с проверкой типов JSX, используя функциональный компонент нового типа. У меня до сих пор есть ветка, мог бы поклясться, что сделал пиар с просьбой о помощи, не могу найти его обратно...
Хорошо, если type должен запрещать массивы узлов, это не означает, что он должен запрещать ReactText
, ReactPortal
, boolean
, null
и undefined
, а также то, что делает использование ReactElement
.
Какой смысл запрещать эти дополнительные типы?
Самый полезный комментарий
В настоящее время я оборачиваю
children
вReact.Fragment
, чтобы обойти это.