将 React 组件作为 arg 传递给 TypeScript 函数:强加组件“props”的最小形状

Cri*_*ian 5 typescript reactjs typescript-generics

我有一个带有签名的 TypeScript 函数:

function connectRRC<C extends ComponentType<any>>(component: C)
Run Code Online (Sandbox Code Playgroud)

目前接受任何组件。

我只想接受“props”中具有给定属性的组件。例如“id:字符串”。

正在做:

function connectRRC<C extends ComponentType<{ id: string }>>(component: C)
Run Code Online (Sandbox Code Playgroud)

不起作用,参见 这个解释

ComponentType在 React 中定义如下:

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;

interface ComponentClass<P = {}, S = ComponentState> extends StaticLifecycle<P, S> {
    new (props: P, context?: any): Component<P, S>;
    propTypes?: WeakValidationMap<P>;
    contextType?: Context<any>;
    contextTypes?: ValidationMap<any>;
    childContextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}

interface FunctionComponent<P = {}> {
    (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
    propTypes?: WeakValidationMap<P>;
    contextTypes?: ValidationMap<any>;
    defaultProps?: Partial<P>;
    displayName?: string;
}
Run Code Online (Sandbox Code Playgroud)

预先感谢您的任何提示!

更新

@sam256 提供了部分工作答案,我认为这是可以接受的。然而,我发现其他用例不起作用,没有找到合理的解释。这个TS Playground 链接展示了它们。

正如预期的那样,这有效:

class GoodComponent2 extends React.Component<{id:string, otherProp:number} & { somethingElse: boolean }> {}
connectRRC(GoodComponent2)
Run Code Online (Sandbox Code Playgroud)

但以下方法不起作用:

class BadComponent3<P = { somethingElse: boolean }> extends React.Component<{id:string, otherProp:number} & P> {}
connectRRC(BadComponent3)

class BadComponent4<P = {}> extends React.Component<{id:string, otherProp:number} & P> {}
connectRRC(BadComponent4)
Run Code Online (Sandbox Code Playgroud)

sam*_*256 1

我有一个部分答案。

type RequiredProps = {id:string}

function connectRRC<T extends RequiredProps>(component: React.FC<T>){}

const goodComponent = (props:{id:string, otherProp:number}) => <div />
const badComponent = (props:{otherProp:number}) => <div />

connectRRC(goodComponent)
connectRRC(badComponent) //typescript error
Run Code Online (Sandbox Code Playgroud)

这几乎如您所愿,因为 Typescript 现在正在推断T并确保它扩展RequiredProps

唯一的问题是,对于完全没有 props 传递的组件,这不会生成错误。这不会产生错误:

const noPropsComponent = (props:{})=><div />
connectRRC(noPropsComponent)
Run Code Online (Sandbox Code Playgroud)

原因又是逆变,至少部分原因是,尽管我不完全理解编译器在这里做什么。

似乎发生的情况是 TS 没有推断T{}因此无法满足约束(任何人都可以解释为什么不这样做吗?)

相反,它看起来T至少假设 是RequiredProps(约束),然后只检查是否component满足React.FC<RequiredProps>,它这样做RequiredProps是因为 处于相反的变体位置。

我不确定有什么好方法可以克服这个问题,部分原因是我不确定我是否完全理解 TS 为何会这样做。具体来说,我不明白为什么它不推断T{}并因不满足RequiredProps约束而失败。

希望论坛里的其他人能帮忙...

操场