代码之家  ›  专栏  ›  技术社区  ›  Asaf Aviv

如何编写提取传入组件的属性类型的泛型

  •  1
  • Asaf Aviv  · 技术社区  · 6 年前

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

    假设我传入一个组件,其类型为 React.FunctionComponent<IMovieShowcase>

    如何提取 IMovieShowcase

    function renderWithProviders<T How to extract type of T<Props>>(
      Component: T, props: // props should be IMovieShowcase
    ) { 
      return (
        <MemoryRouter>
          <MuiThemeProvider theme={createMuiTheme()}>
            <Component {...props} />
          </MuiThemeProvider>
        </MemoryRouter>
      );
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   skovy    6 年前

    我们可以用typescript的 type inference in conditional types

    这个 InferProps 接受名为 Component . 所以它可以作为 InferProps<YourComponent> 返回道具的类型。据我所知 ComponentClass FunctionComponent 是有效的react组件的类型。因为我们必须同时处理这两个问题,所以可以使用嵌套条件(因此 ? )

    第一个条件语句 Component extends React.ComponentClass<infer Props> 是说如果我们 组成部分 扩展 React.ComponentClass 然后 infer 这个 Props 并返回该类型。如果不是,那就检查一下 Component extends React.FunctionComponent<infer Props> . 如果 组成部分 扩展 React.FunctionComponent 然后 推断 这个 道具 并返回该类型。否则,返回 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

    推荐文章