我们可以用typescript的
type inference in conditional types
。
这个
InferProps
接受名为
Component
. 所以它可以作为
InferProps<YourComponent>
返回道具的类型。据我所知
ComponentClass
和
FunctionComponent
是有效的react组件的类型。因为我们必须同时处理这两个问题,所以可以使用嵌套条件(因此
?
)
第一个条件语句
Component extends React.ComponentClass<infer Props>
是说如果我们
组成部分
扩展
React.ComponentClass
然后
infer
这个
Props
并返回该类型。如果不是,那就检查一下
Component extends React.FunctionComponent<infer Props>
. 如果
组成部分
扩展
React.FunctionComponent
然后
推断
这个
道具
并返回该类型。否则,返回
never
因为我们不知道如何处理或是什么,所以我们无法推断道具。
type InferProps<
Component extends ComponentTypes
> = Component extends React.ComponentClass<infer Props>
? Props
: Component extends React.FunctionComponent<infer Props>
? Props
: never;
在您提供的代码的简化示例中使用:
import * as React from "react";
type ComponentTypes = React.ComponentClass<any> | React.FunctionComponent<any>;
type InferProps<
Component extends ComponentTypes
> = Component extends React.ComponentClass<infer Props>
? Props
: Component extends React.FunctionComponent<infer Props>
? Props
: never;
function renderWithProviders<T extends ComponentTypes>(
Component: T,
props: InferProps<T>
) {
return <Component {...props} />;
}
class Test extends React.Component<{ foo: string }> {
render() {
return null;
}
}
const Another = (props: { baz: number }) => null;
// Valid:
renderWithProviders(Test, { foo: "bar" });
// Valid:
renderWithProviders(Another, { baz: 1 });
// Invalid:
// Object literal may only specify known properties,
// and 'baz' does not exist in type '{ foo: string; }'
renderWithProviders(Test, { foo: "bar", baz: "foo" });
// Invalid:
// The expected type comes from property 'baz' which is
// declared here on type '{ baz: number; }'
renderWithProviders(Another, { baz: "nope" });