React TS:我可以在不进行类型转换的情况下做到这一点吗? “可以用可能不相关的任意类型实例化”
Posted
技术标签:
【中文标题】React TS:我可以在不进行类型转换的情况下做到这一点吗? “可以用可能不相关的任意类型实例化”【英文标题】:React TS: Can I do this without typecasting? "could be instantiated with an arbitrary type which could be unrelated" 【发布时间】:2021-06-23 21:41:04 【问题描述】:我有这段代码(这是我真实代码的简化版本,希望我没有删除任何重要的东西)
import React, ReactElement, ReactNode, createElement from "react";
interface WithChildren
children: ReactNode;
type WrapperType<WTProps> = (
props: WithChildren & WTProps
) => ReactElement | null;
interface SetProps<P>
wrap: WrapperType<P>;
children: ReactNode;
[x: string]: unknown;
export function Set<WProps>(props: SetProps<WProps>)
const wrap, children, ...rest = props;
return createElement(wrap, ...rest, children );
interface WrapperProps
children: ReactNode;
foo: string;
const ChildWrapper: React.FC<WrapperProps> = ( foo, children ) =>
return (
<div>
<h1>ChildWrapper</h1>
<p>foo</p>
children
</div>
);
;
export default function App()
return (
<Set wrap=ChildWrapper foo="bar">
<h1>Hello CodeSandbox</h1>
</Set>
);
createElement
行给出了这个错误
No overload matches this call.
The last overload gave the following error.
Argument of type ' children: React.ReactNode; ' is not assignable to parameter of type 'Attributes & WithChildren & WProps'.
Type ' children: React.ReactNode; ' is not assignable to type 'WProps'.
'WProps' could be instantiated with an arbitrary type which could be unrelated to ' children: React.ReactNode; '
我可以通过这样的类型转换来“修复”它
return createElement(wrap, ...rest, children as WProps & WithChildren);
但这消除了类型安全性。
我发现了这个类似的问题ts: 'Props' could be instantiated with an arbitrary type which could be unrelated to another type,他们使用Omit<>
来解决它。但我不知道如何在我的情况下应用它。
有没有什么方法可以在不进行类型转换的情况下做到这一点?
编辑:这是一个代码框,显示错误https://codesandbox.io/s/optimistic-microservice-ck7nf?file=/src/App.tsx
以及错误信息的截图
【问题讨论】:
你的代码中好像没有这个错误 @zixiCat 我添加了一个代码框链接,您可以在其中看到错误 我开始给你写一个很长的答案,但实际上我现在所处的位置children
的类型被推断为 Set
的孩子的类型,而不是ChildWrapper
所以WrapperProps
必须是JSX.Element
而不是ReactNode
。 tsplay.dev/WKkpzW我看看能不能更好的控制推理。
【参考方案1】:
哦,我改变了很多。至于为什么初始代码会出错,我对此感到有些困惑。
也许Set<WProps>(props: SetProps<WProps>)
中的WProps
无法从实例中获取正确的初始类型。
我的解决方案:
import React, ReactElement, ReactNode from 'react';
export function Set<WProps>(
props: WProps &
wrap: (props: WProps) => ReactElement;
)
const wrap: Wrap = props;
return <Wrap ...props />;
interface WrapperProps
children: ReactNode;
foo: string;
const ChildWrapper = ( foo, children : WrapperProps) =>
return (
<div>
<h1>ChildWrapper</h1>
<p>foo</p>
children
</div>
);
;
export default function App()
return (
<Set<WrapperProps> wrap=ChildWrapper foo='1'>
<h1>Hello CodeSandbox</h1>
</Set>
);
我的tsconfig
中的strictFunctionTypes
属性设置为false
(默认值),所以没有复现。
【讨论】:
非常感谢!但是,我的设计目标之一是要求所有包装器都将children
作为道具。在这里,我们可以从WrapperProps
中删除children
,并从ChildWrapper
中删除对儿童的支持,它仍然可以编译。这就是为什么我有一个单独的WithChildren
接口,我加入了WTProps
。可以在这里强制执行吗?
@Tobbe:不,这是另一个问题,如下图所示,点击more detail about this _________________________________________________________________const a: (p: string) => void = () => ; // No error thrown
之前的代码有错误而你没有的原因是wrap
之前被从props中删除了,如果WProps
包含wrap
,这是一个潜在的问题。您正在传递整个props
对象,我们知道它可以分配给WProps
,因此可以修复错误:)
另外你也不需要<Set<WrapperProps>>
里面的<WrapperProps>
注解。看起来它自己推断得很好。以上是关于React TS:我可以在不进行类型转换的情况下做到这一点吗? “可以用可能不相关的任意类型实例化”的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript:我可以在不编写 index.ts 文件的情况下导入文件夹吗?