Typescript React:访问组件属性类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43230765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:25:39  来源:igfitidea点击:

Typescript React: Access component property types

reactjstypescript

提问by Girafa

npm package @types/reactallows us to use React inside of our TypeScript apps. We define components as

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

type Props = {...}

type State = {...}

export default class MyComponent extends React.Component<Props, State> {
}

here we have to declare types for component props and state (in type variables).

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

After we declared that types, TypeScript uses that to validate the usage of our component (the shape of props passed to it).

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

I want to create a container around such a component. The container will reuse the props of the component. But in order to create another component with the same props I have to redeclare the types for props again. Or export them from the original component file and import into container:

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

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

// container file
import MyComponent, { Props } from './original'

But I'm already importing the MyComponentfrom that file. This component already contains information about the props it consumes (thanks to type variables in React.Component).

但我已经MyComponent从那个文件导入了。这个组件已经包含了关于它消耗的 props 的信息(感谢在 中输入变量React.Component)。

The question is how do I access that information from the component class itself without explicitly exporting/importing the type for props?

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

I want something like:

我想要这样的东西:

import MyComponent from './MyComponent'

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

export default class MyContainer extends React.Component<Props, {}> {}

回答by Sebastien Lorber

2019: noticed all answers above are quite outdated so here is a fresh one.

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



Lookup type

查找类型

With newer TS versions you can use lookup types.

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

type ViewProps = View['props']

Despite being very convenient, that will only work with class components.

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



React.ComponentProps

React.ComponentProps

The React typedefs ship with an utility to extract the type of the props from any component.

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

type ViewProps = React.ComponentProps<typeof View>

type InputProps = React.ComponentProps<'input'>

This is a bit more verbose, but unlike the type lookup solution:

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

  • the developer intent is more clear
  • this will work with BOTH functional components and class components
  • 开发者意图更明确
  • 这将适用于功能组件和类组件

All this makes this solution the most future-proofone: if you decide to migrate from classes to hooks, you won't need to refactor any client code.

所有这一切都使这个解决方案成为最具前瞻性的解决方案:如果您决定从类迁移到钩子,您将不需要重构任何客户端代码。

回答by Oliver Joseph Ash

Starting with TypeScript 2.8, you can use conditional types, e.g. given:

从 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>;

We can define these helpers:

我们可以定义这些助手:

type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never

And use them like so:

并像这样使用它们:

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

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

// $ExpectType MyStatelessComponentProps
type MyStatelessComponentPropsExtracted = GetComponentProps<typeof MyStatelessComponent>

Update 2018-12-31: this is now available in the official React typings via React.ComponentProps.

2018 年 12 月 31 日更新:现在可以通过React.ComponentProps.

回答by niba

To take a type of properties from component

从组件中获取一种类型的属性

type Props = typeof MyComponent.defaultProps;

You can ask yourself why I'm taking typeof from defaultProps and not from propTypes. To explain that lets take a look at the definition file

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

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

As you can see propTypes are wrapped in ValidationMap and it's not easy to get raw types. Fortunately, defaultProps have raw types

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

回答by Oliver Joseph Ash

Given a React component:

给定一个 React 组件:

import React, { ComponentType, StatelessComponent } from 'react';

const MyComponent: StatelessComponent<{ foo: string }> = props => <div>{props.foo}</div>;

You can do:

你可以做:

const getProps = function<Props> (_MyComponent: ComponentType<Props>): Props {
  return {} as Props;
};
const props = getProps(MyComponent);

// { foo: string; }
type MyComponentProps = typeof props;

Alternatively, you can augment the React typings to add a GetComponentPropshelper:

或者,您可以扩充 React 类型以添加GetComponentProps帮助程序:

import React from 'react';

type NonNullable < T > = T & {};

declare module 'react' {
  // Add helper for accessing props type of given component. Based off of
  // https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182.
  type GetComponentProps < C extends ComponentType < any > > = NonNullable<C['_doNotUse_props']>;

  // We use interface merging to append properties to these types
  interface StatelessComponent<P = {}> {
    // eslint-disable-next-line camelcase
    _doNotUse_props?: P;
  }
  interface ComponentClass<P = {}> {
    // eslint-disable-next-line camelcase
    _doNotUse_props?: P;
  }
}

Usage looks like this:

用法如下所示:

// { foo: string; }
type MyComponentProps = React.GetComponentProps<typeof MyComponent>;

I originally posted this in https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182.

我最初将其发布在https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182 中

回答by Sergey Volkov

That's my solution of how to get props from component

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


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;


If you use functional component, class component or styled component that solution should help you.
How to use:

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

type Props = PropsOf<typeof YourComponent>

You can add this to 'react.d.ts'

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