Dim*_*nis 6 javascript typescript reactjs react-typescript
我有这个示例组件
import React, { FC, ReactNode, useMemo } from "react";
import PropTypes from "prop-types";
type Props = {
children: ((x: number) => ReactNode) | ReactNode;
};
const Comp: FC<Props> = function Comp(props) {
const val = useMemo(() => {
return 1;
}, []);
return (
<div>
{typeof props.children === "function"
? props.children(val)
: props.children}
</div>
);
};
Comp.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
};
export default Comp;
Run Code Online (Sandbox Code Playgroud)
我的意图是children组件的道具可以是
a node,它被描述为
任何可以渲染的东西:数字、字符串、元素或包含这些类型的数组(或片段)。
a function, (或“渲染道具”),它只是从组件内部获取一个值并返回另一个node
这里的重点是明确的,children可以是一个 ( node,这几乎是一切) 或另一个 ( 这只是一个function)
但是,我在类型检查方面面临以下问题。
? props.children(val)
此表达式不可调用。并非所有类型为“功能 | ”的成分 ((x: number) => ReactNode) | (字符串 & {}) | (数字和{})| (false & {}) | (真 & {}) | ({} & 字符串) | ({} & 数字) | ({} & 假) | ({} & 真) | (((x: number) => ReactNode) & 字符串)
我不明白这个错误。
Props类型更改为type Props = {
children: (x: number) => ReactNode;
};
Run Code Online (Sandbox Code Playgroud)
并依靠 React 自己type PropsWithChildren<P> = P & { children?: ReactNode };来处理children不是函数的情况,然后我得到错误
(property) children?: PropTypes.Validator<(x: number) => React.ReactNode> Type 'Validator' 不能分配给 type 'Validator<(x: number) => ReactNode>'。类型 'ReactNodeLike' 不能分配给类型 '(x: number) => ReactNode'。类型 'string' 不可分配给类型 '(x: number) => ReactNode'.ts(2322) Comp.tsx(5, 3):预期的类型来自属性 'children',它在类型上声明
在线上 children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
唯一的解决方案是将Props类型保留为
type Props = {
children: (x: number) => ReactNode;
};
Run Code Online (Sandbox Code Playgroud)
并且还将 the 更改Comp.propTypes为children: PropTypes.func.isRequired,这不是我想要的,因为我想明确表示。
我怎样才能保持代码明确,如本问题开头所示,并且没有类型检查抛出错误?
children类型为ReactNode,它&与children包含在Props.ReactNode是一种相当宽的类型,限制了编译器将children联合类型缩小到与第 1 点相结合的可调用函数的能力。一个解决方案是省略FC和使用更窄的类型,而不是ReactNode有利于类型安全:
type Renderable = number | string | ReactElement | Renderable[]
type Props = {
children: ((x: number) => Renderable) | Renderable;
};
Run Code Online (Sandbox Code Playgroud)
首先,这里是内置的 React 类型:
type Renderable = number | string | ReactElement | Renderable[]
type Props = {
children: ((x: number) => Renderable) | Renderable;
};
Run Code Online (Sandbox Code Playgroud)
1.) 你FC<Props>用来输入Comp. FC内部已经包含一个children类型为 as的声明ReactNode,它与children来自的定义合并Props:
type Props = { children: ((x: number) => ReactNode) | ReactNode } &
{ children?: ReactNode }
// this is how the actual/effective props rather look like
Run Code Online (Sandbox Code Playgroud)
2.) 查看ReactNode类型,您会发现类型变得相当复杂。ReactNode包括类型{}via ReactFragment,它是除nulland之外的所有内容undefined的超类型。我不知道这种类型形状背后的确切决定,microsoft/TypeScript#21699暗示了历史和向后兼容的原因。
因此,children类型比预期的要宽。这会导致您的原始错误:类型保护typeof props.children === "function"无法将类型“混乱”正确缩小到function了。
React.FC最后,React.FC它只是一个具有额外属性的函数类型,如propTypes,displayName等,具有自以为是的宽children类型。省略FC此处将为编译器和 IDE 显示提供更安全、更易于理解的类型。如果我把你定义Anything that can be rendered为children,这可能是:
import React, { ReactChild } from "react";
// You could keep `ReactNode`, though we can do better with more narrow types
type Renderable = ReactChild | Renderable[]
type Props = {
children: ((x: number) => Renderable) | Renderable;
};
const Comp = (props: Props) => {...} // leave out `FC` type
Run Code Online (Sandbox Code Playgroud)
FC类型不children您可以定义自己的FC版本,其中包含React.FC除这些宽children类型之外的所有内容:
type FC_NoChildren<P = {}> = { [K in keyof FC<P>]: FC<P>[K] } & // propTypes etc.
{ (props: P, context?: any): ReactElement | null } // changed call signature
const Comp: FC_NoChildren<Props> = props => ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8781 次 |
| 最近记录: |