Typescript React:访问组件属性类型

Gir*_*afa 24 typescript reactjs

npm包@types/react允许我们在TypeScript应用程序中使用React.我们将组件定义为

type Props = {...}

type State = {...}

export default class MyComponent extends React.Component<Props, State> {
}
Run Code Online (Sandbox Code Playgroud)

这里我们必须声明组件props和state的类型(在类型变量中).

在我们声明了类型之后,TypeScript使用它来验证组件的使用(传递给它的props的形状).

我想围绕这样一个组件创建一个容器.容器将重用组件的props.但是为了创建具有相同道具的另一个组件,我必须再次重新声明道具的类型.或者从原始组件文件中导出它们并导入到容器中:

// original file
export type Props = {...}

// container file
import MyComponent, { Props } from './original'
Run Code Online (Sandbox Code Playgroud)

但我已经MyComponent从该文件导入了.此组件已包含有关其消耗的道具的信息(感谢类型变量React.Component).

问题是如何从组件类本身访问该信息而不显式导出/导入props的类型

我想要的东西:

import MyComponent from './MyComponent'

type Props = MyComponent.Props // <= here access the component prop types

export default class MyContainer extends React.Component<Props, {}> {}
Run Code Online (Sandbox Code Playgroud)

Seb*_*ber 43

2019:注意到上面的所有答案都已经过时了,所以这里是一个新鲜的答案。


查询类型

使用较新的TS版本,您可以使用查找类型。

type ViewProps = View['props']
Run Code Online (Sandbox Code Playgroud)

尽管非常方便,但这仅适用于类组件


React.ComponentProps

React typedef附带了一个实用程序,可从任何组件中提取道具的类型。

type ViewProps = React.ComponentProps<typeof View>

type InputProps = React.ComponentProps<'input'>
Run Code Online (Sandbox Code Playgroud)

这有点冗长,但是与类型查找解决方案不同:

  • 开发者的意图更加明确
  • 这将与功能组件和类组件一起使用

所有这些使该解决方案成为最可靠的解决方案:如果您决定从类迁移到挂钩,则无需重构任何客户端代码。

  • 您甚至可以通过在字符串中传递`React.ComponentProps &lt;'input'&gt;`来获取本地元素的道具,例如&lt;input /&gt;。谢谢 :) (5认同)
  • 不幸的是,这不适用于“typeof View&lt;ViewData&gt;”等通用类型组件 (4认同)
  • 很好的答案!但是它没有考虑 `defaultProps` 。这个的作用是:`type MyCompProps = JSX.LibraryManagedAttributes&lt;typeof MyComp, React.ComponentProps&lt;typeof MyComp&gt;&gt;`。请参阅 https://github.com/Microsoft/TypeScript/issues/26704#issuecomment-416429613 (3认同)

Oli*_*Ash 23

从TypeScript 2.8开始,您可以使用条件类型,例如:

interface MyComponentProps { bar: string; }
declare const MyComponent: React.Component<MyComponentProps>;

interface MyComponentClassProps { bar: string; }
declare const MyComponentClass: React.ComponentClass<MyComponentClassProps>;

interface MyStatelessComponentProps { bar: string; }
declare const MyStatelessComponent: React.StatelessComponent<MyStatelessComponentProps>;
Run Code Online (Sandbox Code Playgroud)

我们可以定义这些助手:

type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never
Run Code Online (Sandbox Code Playgroud)

并像这样使用它们:

// $ExpectType MyComponentProps
type MyComponentPropsExtracted = GetComponentProps<typeof MyComponent>

// $ExpectType MyComponentClassProps
type MyComponentClassPropsExtracted = GetComponentProps<typeof MyComponentClass>

// $ExpectType MyStatelessComponentProps
type MyStatelessComponentPropsExtracted = GetComponentProps<typeof MyStatelessComponent>
Run Code Online (Sandbox Code Playgroud)

更新2018-12-31:现在可以在官方的React打字中找到React.ComponentProps.


nib*_*iba 7

从组件获取某种类型的属性

type Props = typeof MyComponent.defaultProps;
Run Code Online (Sandbox Code Playgroud)

你可以问自己为什么我从 defaultProps 中获取 typeof 而不是从 propTypes 中获取。为了解释这一点,让我们看一下定义文件

  interface ComponentClass<P> {
        new(props?: P, context?: any): Component<P, ComponentState>;
        propTypes?: ValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        childContextTypes?: ValidationMap<any>;
        defaultProps?: P;
        displayName?: string;
    }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,propTypes 被包装在 ValidationMap 中,并且获取原始类型并不容易。幸运的是,defaultProps 有原始类型


Ser*_*kov 5

这是我如何从组件获取道具的解决方案


type Propsable = {
  FC: React.FC;
  C: React.Component;
  CC: React.ComponentClass<any>;
  F: (...args: any) => any;
}
type PropsOfFC<C extends Propsable["FC"]> = {
  [K in keyof C["propTypes"]]: C["propTypes"][K] extends React.Validator<infer P>
    ? P
    : K
};
type PropsOfF<C extends Propsable["F"]> = Parameters<C>[0]
type PropsOfC<C extends Propsable["C"]> = C extends React.Component<infer P> ? P : never;
type PropsOfCC<C extends Propsable["CC"]> = C extends React.ComponentClass<infer P> ? P : never;


type PropsOf<C extends ValueOf<Propsable>> =
  C extends Propsable["FC"] ? PropsOfFC<C> :
  C extends Propsable["C"] ? PropsOfC<C> :
  C extends Propsable["CC"] ? PropsOfCC<C> :
  C extends Propsable["F"] ? PropsOfF<C> : any;


Run Code Online (Sandbox Code Playgroud)

如果您使用功能组件、类组件或样式组件,该解决方案应该对您有所帮助。
如何使用:

type Props = PropsOf<typeof YourComponent>
Run Code Online (Sandbox Code Playgroud)

您可以将其添加到“react.d.ts”