我创建了一个简单的HOC,可以translate在组件中注入方法。
translate
export interface IMessageProps { translate: (key: string) => string; } export const message = <P extends object>( Component: React.ComponentType<P & IMessageProps> ): React.SFC<P & IMessageProps> => (props: P) => { const translate = (key: string): string => messages[key]; return <Component {...props} translate={translate}/>; };
用法:
class MyComponent extends React.Component<IMessageProps, {}> { render() { return ( <>{this.props.translate('hello.world')}</> ); } } export default message(MyComponent);
当我想调用组件时会出现问题,<MyComponent/>因为tsc抱怨该属性translate未传递给,MyComponent并且期望类似之类的东西<MyComponent translate={...}/>。
<MyComponent/>
MyComponent
<MyComponent translate={...}/>
Type '{}' is not assignable to type 'IntrinsicAttributes & IMessageProps & { children?: ReactNode; }'. Type '{}' is not assignable to type 'IMessageProps'. Property 'translate' is missing in type '{}'.
所以我的问题是: 如何绕开这个假错误? 我不想translate选择,IMessageProps因为tslint会抱怨Cannot invoke an object which is possibly 'undefined'。
IMessageProps
Cannot invoke an object which is possibly 'undefined'
编辑
Typescript 3.2破坏了下面的代码。直到3.2为止,除jsx标记外,不允许使用泛型类型参数进行传播操作,并且在那里没有进行严格检查。这个问题改变了这一点。扩展操作没有得到更严格的检查,这可以分解代码。我们可以做的最简单的调整是在上使用类型断言props:
props
export const message = <P extends IMessageProps>( Component: React.ComponentType<P> ): React.SFC<Pick<P, Exclude<keyof P, keyof IMessageProps>>> => (props: Pick<P, Exclude<keyof P, keyof IMessageProps>>) => { const translate = (key: string): string => messages[key]; return <Component {...props as P} translate={translate} />; };
3.2之前
您可以仅从IMessageProps返回的SCF使用中排除的属性,以Pick从中选择属性P并Exclude排除的键IMessageProps
SCF
Pick
P
Exclude
export interface IMessageProps { translate: (key: string) => string; } export const message = <P extends IMessageProps>( Component: React.ComponentType<P> ): React.SFC<Pick<P, Exclude<keyof P, keyof IMessageProps>>> => (props: Pick<P, Exclude<keyof P, keyof IMessageProps>>) => { const translate = (key: string): string => messages[key]; return <Component {...props} translate={translate} />; }; class MyComponent extends React.Component<IMessageProps, {}> { render() { return ( <>{this.props.translate('hello.world')}</> ); } } const MyComponentWrapped = message(MyComponent); let d = <MyComponentWrapped /> // works
3.5及以上
您可以使用Omit<P, keyof IMessageProps>代替Pick<P, Exclude<keyof P, keyof IMessageProps>>
Omit<P, keyof IMessageProps>
Pick<P, Exclude<keyof P, keyof IMessageProps>>