npm package @types/react
允许我们在TypeScript应用程序中使用React。
我们将组件定义为
type Props = {...}
type State = {...}
export default class MyComponent extends React.Component<Props, State> {
}
这里我们必须声明组件props和state的类型(在类型变量中)。
在我们声明了这些类型之后,TypeScript使用它来验证我们组件的用法(传递给它的props的形状)。
我想在这样的组件周围创建一个容器。容器将重用组件的props。但是为了创建具有相同道具的另一个组件,我必须再次重新声明道具的类型。或者从原始组件文件中导出它们并导入容器:
// original file
export type Props = {...}
// container file
import MyComponent, { Props } from './original'
但我已经从该文件中导入了MyComponent
。此组件已包含有关其消耗的道具的信息(感谢React.Component
中的类型变量)。
问题是如何在不明确导出/导入道具类型的情况下从组件类本身访问该信息?
我想要类似的东西:
import MyComponent from './MyComponent'
type Props = MyComponent.Props // <= here access the component prop types
export default class MyContainer extends React.Component<Props, {}> {}
答案 0 :(得分:20)
从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>;
我们可以定义这些助手:
type GetComponentProps<T> = T extends React.ComponentType<infer P> | React.Component<infer P> ? P : never
并像这样使用它们:
// $ExpectType MyComponentProps
type MyComponentPropsExtracted = GetComponentProps<typeof MyComponent>
// $ExpectType MyComponentClassProps
type MyComponentClassPropsExtracted = GetComponentProps<typeof MyComponentClass>
// $ExpectType MyStatelessComponentProps
type MyStatelessComponentPropsExtracted = GetComponentProps<typeof MyStatelessComponent>
更新2018-12-31 :现在可通过React.ComponentProps
在官方的React打字中找到。
答案 1 :(得分:13)
2019 :注意到以上所有答案都已经过时,因此这里是一个全新的答案。
使用更新的TS版本,您可以使用查找类型。
type ViewProps = View['props']
尽管非常方便,但仅适用于类组件。
React typedef附带了一个实用程序,可从任何组件中提取道具的类型。
type ViewProps = React.ComponentProps<typeof View>
这有点冗长,但是与类型查找解决方案不同:
所有这些使该解决方案成为最具前瞻性解决方案:如果您决定从类迁移到挂钩,则无需重构任何客户端代码。
答案 2 :(得分:2)
从组件中获取一种属性
type Props = typeof MyComponent.defaultProps;
你可以问问自己为什么我从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;
}
正如您所看到的,propTypes包含在ValidationMap中,并且它不容易获得原始类型。幸运的是,defaultProps有原始类型
答案 3 :(得分:2)
给出一个React组件:
import React, { ComponentType, StatelessComponent } from 'react';
const MyComponent: StatelessComponent<{ foo: string }> = props => <div>{props.foo}</div>;
你可以这样做:
const getProps = function<Props> (_MyComponent: ComponentType<Props>): Props {
return {} as Props;
};
const props = getProps(MyComponent);
// { foo: string; }
type MyComponentProps = typeof props;
或者,您可以扩充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;
}
}
用法如下:
// { foo: string; }
type MyComponentProps = React.GetComponentProps<typeof MyComponent>;
我最初在https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24182发布了此内容。
答案 4 :(得分:0)
这是我如何从组件中获取道具的解决方案
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;
如果您使用功能组件,类组件或样式化组件,则解决方案将为您提供帮助。
使用方法:
type Props = PropsOf<typeof YourComponent>
您可以将其添加到“ react.d.ts”
答案 5 :(得分:-1)
您可以使用import * as
语法:
import * as MC from './MyComponent';
type Props = MC.Props;