如何编写泛型来提取传入组件的prop类型

时间:2019-09-09 01:10:13

标签: reactjs typescript

我该如何编写一个接受组件并将其prop类型用作第二个参数类型的泛型

可以说我传入的类型为/var/lib/docker/containers/<containerid>/<path>

我如何提取React.FunctionComponent<IMovieShowcase>的类型

IMovieShowcase

1 个答案:

答案 0 :(得分:1)

我们可以使用TypeScript的type inference in conditional types

InferProps接受名为Component的通用名称。因此它可以用作InferProps<YourComponent>来返回道具的类型。据我所知,有ComponentClassFunctionComponent类型是有效的React组件。由于必须同时处理这两种情况,因此我们可以使用嵌套条件(因此使用双?)。

第一个条件语句Component extends React.ComponentClass<infer Props>表示如果我们的Component扩展了React.ComponentClass,则infer扩展了Props并返回了该类型。如果不是,请检查Component extends React.FunctionComponent<infer Props>。如果Component扩展了React.FunctionComponent,则infer Props并返回该类型。否则,请返回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" });

Edit infer-props