我正在尝试编写更高阶的组件来检查用户是否经过身份验证。我正在使用React 15.5.4和@ types / react 15.0.21,我的(简化)代码如下所示:
import * as React from 'react';
interface IAuthProps {
authenticated: boolean
}
function authenticated1<Props extends Object>(wrapped: React.ComponentClass<Props> | React.SFC<Props>):
React.SFC<Props & IAuthProps> {
return (props: Props & IAuthProps): React.ReactElement<any> => {
if (props.authenticated) {
return React.createElement(wrapped, props);
} else {
return <h1>Unauthorized!</h1>
}
}
}
但是,在createElement
:
TS2345:Argument of type 'ComponentClass<Props> | StatelessComponent<Props>' is not assignable to parameter of type 'ComponentClass<Props>'.
Type 'StatelessComponent<Props>' is not assignable to type 'ComponentClass<Props>'.
Type 'StatelessComponent<Props>' provides no match for the signature 'new (props?: Props | undefined, context?: any): Component<Props, ComponentState>'
由于@types/react
将React.createElement
声明为重载函数和Typescript can't resolve overloads with union types,因此错误并不令人惊讶。
但是@types/react
为联合中的每个类型提供了合格的重载(SFCEelement
继承ReactElement
,因此返回类型是兼容的):
function createElement<P>(
type: ComponentClass<P>,
props?: Attributes & P,
...children: ReactNode[]): ReactElement<P>;
function createElement<P>(
type: SFC<P>,
props?: Attributes & P,
...children: ReactNode[]): SFCElement<P>;
为了使代码编译,我只需要强制Typescript考虑联合类型中相应分支的重载,但我不知道如何做到这一点。
如何区分ComponentClass
和SFC
以使Typescript为类型检查选择相应的重载?
PS:目前我只是强迫它通过传递wrapped as React.ComponentClass<Props>
来选择第一个重载,这是安全的,因为两个重载调用同一个接受两种参数类型的运行时函数,但我宁愿不喜欢在这里“欺骗”,而不是类型系统保证安全。
答案 0 :(得分:0)
我认为目前无法做到这一点,因为它需要更改类型定义。
要使用类型保护功能,它允许缩小对象的类型,我们需要扩展一些定义。
interface StatelessComponent<P> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any>;
type: 'StatelessComponent'; // NEW ONE
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
interface ComponentClass<P> {
new (props?: P, context?: any): Component<P, ComponentState>;
type: 'ComponentClass'; // NEW ONE
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
childContextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
然后我们就可以做那样的事了
function createElementWrapper<Props extends Object>(wrapped: React.ComponentClass<Props> | React.SFC<Props>, props: any) {
if (wrapped.type === "StatelessComponent") {
return React.createElement(wrapped, props); // wrapped is a StatelessComponent
} else {
return React.createElement(wrapped, props); // wrapped is a ComponentClass
}
}
在绝对式存储库中创建有关此问题的问题可能是个好主意