英文:
How do default values and union types work in React components?
问题
以下是翻译好的部分:
So basically I wonder why does setting the default value to a prop break a condition for types.
所以基本上我想知道为什么将默认值设置为属性会破坏类型的条件。
And the second question is why does passing children as a prop work with types fine but when calling children function in JSX it doesn't see correct types.
第二个问题是,为什么将子元素作为属性传递可以正常工作,但在JSX中调用子元素函数时类型不正确。
That's a tricky question, tried to find an answer in google, but didn't manage it
这是一个棘手的问题,尝试在Google中找到答案,但没有成功。
英文:
I described my question with examples here:
https://codesandbox.io/s/gracious-diffie-hs57tc?file=/src/App.tsx
So basically I wonder why does setting the default value to a prop break a condition for types.
And the second question is why does passing children as a prop work with types fine but when calling children function in JSX it doesn't see correct types.
That's a tricky question, tried to find an answer in google, but didn't manage it
答案1
得分: 0
以下是翻译好的内容:
.defaultProps
首先,我想明确一点,我发现它可能会在将来被弃用,但它仍然有效...
要定义props的默认值,可以使用defaultProps
静态字段:
type Props = {
flag: boolean;
};
const MyComp = ({ flag }: Props) => <p>{flag ? "是" : "否"}</p>;
MyComp.defaultProps = {
flag: false
};
React.FC<>
我注意到,当我们在组件的第一个使用中移除flag
时,会出现和第二个使用相同的问题。但我成功通过为组件添加React.FC<ComponentProps>
类型来修复它:
const Component: React.FC<ComponentProps> = ({ flag, children }: ComponentProps /* 如果您愿意,可以从此处删除参数类型 */) => {
// ...
};
现在,这段代码会报告isOpen
不存在,而不是同时报告"title
和isOpen
都是any
"的问题:
<Component children={({ title, isOpen }) => <>{isOpen ? title : "已关闭"}</>} />
// ^^^^^^
// 属性'isOpen'在类型'{ title: string; }'上不存在。
关于children类型推断
关于您的最后一个问题,不幸的是,我没有找到任何合乎逻辑的原因,我认为这看起来像是React TypeScript的一个bug。
我观察到,如果我们移除children的值,会得到以下错误:
<Component>{}<</Component>;
// 类型'never[]'与签名'(props: { title: string; }): ReactNode'不匹配。
因此,我们可以理解TypeScript知道正确的类型是children
,并尝试进行匹配。但出于某种原因,它无法推断出我们提供的函数的类型。作为一种解决方法,您可以严格地为其添加类型,这将起作用(但我承认这不是一个好的解决方案)...
似乎它无法使用这种语法进行类型推断,我认为您应该提交一个错误报告,因为这不是正确的行为。
英文:
I played a little with your sandbox and figured out a few things.
.defaultProps
First of all I'd like to precise I just found it may be deprecated in the future, but it works...
For defining default values to props, you can use the defaultProps
static field:
type Props = {
flag: boolean;
};
const MyComp = ({ flag }: Props) => <p>{flag ? "Yes" : "No"}</p>;
MyComp.defaultProps = {
flag: false
};
React.FC<>
I noticed that when we remove the flag
in the first usage of the component, the same problem as the second appears. But I managed to fix it by adding the type React.FC<ComponentProps>
to the component:
const Component: React.FC<ComponentProps> = ({ flag, children }: ComponentProps /* You can remove the parameter type from here if you want*/) => {
// ...
};
Now, this code tell that isOpen
does not exist, instead of both the "title
and isOpen
are any
" thing:
<Component children={({ title, isOpen }) => <>{isOpen ? title : "Closed"}</>} />
// ^^^^^^
// Property 'isOpen' does not exist on type '{ title: string; }'.
The children type inference
About your last question, unfortunately, I didn't found any logical reason, and I think it looks like a React TypeScript bug.
I observed that if we remove the children value we get the following error:
<Component>{}</Component>
// Type 'never[]' provides no match for the signature '(props: { title: string; }): ReactNode'.
So we understand here that TypeScript is aware that the correct type is children
, and tries to match it. But, for some reason, it is unable to infer the type of the parameter when we give the function. You can, as a workaround, strictly type it and it'll work (but I admit this is not a good solution)...
It seems that it cannot do the type inference with this syntax and in my opinion, you should open a bug report because this is not the correct behavior.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论