TL; DNR::我正在使用TypeScript 3.3.3。有没有更好的方法来声明从HOC注入的我需要的道具,而不会在使用我的组件的代码中看到它们呢?
考虑一个用withNamespaces
HOC装饰的基本组件。使用的库和HOC是任意的,遵循此模式的所有组件都遇到了这个问题。类组件也有一些问题,但这里我将重点介绍函数。
// MyComponent.tsx
import * as React from 'react'
import { withNamespaces, WithNamespaces } from 'react-i18next'
const MyComponent: React.FunctionalComponent = ({ children, t }) => (
<a title={t('my translated text')}>{children}</a>
)
export default withNamespaces('my-component')(MyComponent)
我还有第二个文件,其中包含针对组件的测试。
// MyComponent.spec.tsx
import * as React from 'react'
import { shallow } from 'enzyme'
import MyComponent from './MyComponent'
it('should render', () => {
const wrapper = shallow(<MyComponent>Test</MyComponent>)
expect(wrapper.toExist()).toBeTruthy()
})
现在,由于t
在我的道具中未定义,因此无法编译。我可以尝试通过多种方法解决此问题。在此示例中,第三方库为我们提供了WithNamespaces
类型,该类型定义了t
,还有withNamespaces
注入到组件中的其他内容,我们可以将其用作或合并我们的道具类型定义。
const MyComponent: React.FunctionalComponent<WithNamespaces> = ({children, t}) => ( // ...
现在MyComponent
进行编译,并为我可能的道具提供了很好的类型安全性。但是,现在我的测试文件很生气,因为我没有提供组件定义期望的prop值,例如t
。但是,我们知道这将由HOC注入,因此创建一个模拟程序或为该道具提供一些垃圾值只是令人困惑,而且不需要额外的工作来解决类型问题。
// type is missing the following properties from WithNamespaces: t, etc., etc.
const wrapper = shallow(<MyComponent>Test</MyComponent>)
我可以通过将组件的props局部设置为FunctionalComponent<Partial<WithNamespaces>>
来进行伪造,但是现在我必须有条件地检查我需要或使用t!
(非null断言运算符)的那些prop,似乎不必要地令人讨厌,融化了刚接触TS的人们的大脑,并且看起来有些臭。
我也可以只在我的render函数中(或在类中,任何访问props的方法中)投射props,以向我的消费者隐藏注入的props:
const MyComponent: React.FunctionalComponent = (props) => {
const { children, t } = props as WithNamespaces
return (
<a title={t('my translated text')}>{children}</a>
)
}
但是,这有点手摇且不雅。还有许多其他方法,例如强制转换为任何内容并返回不引用WithNamespaces的内容等,但是肯定有更好的方法吗?
其他
withNamespace
确实有一个定义,该定义使用Omit
pattern从返回的类型中排除WithNamespaces
中的props,但至少在功能组件方面似乎不起作用