![](/img/trans.png)
[英]React Functional component with Typescript: Typescript does not understand changing property types
[英]Typescript React: Access component property types
npm包@types/react
允許我們在TypeScript應用程序內部使用React。 我們將組件定義為
type Props = {...}
type State = {...}
export default class MyComponent extends React.Component<Props, State> {
}
在這里,我們必須聲明組件屬性和狀態的類型(在類型變量中)。
在聲明了這些類型之后,TypeScript將使用該類型來驗證組件的用法(傳遞給它的道具的形狀)。
我想圍繞這樣的組件創建一個容器。 容器將重復使用組件的道具。 但是,為了用相同的道具創建另一個組件,我必須再次聲明道具的類型。 或從原始組件文件中導出它們並導入到容器中:
// 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, {}> {}
2019 :注意到上面的所有答案都已經過時了,所以這里是一個新鮮的答案。
使用較新的TS版本,您可以使用查找類型。
type ViewProps = View['props']
盡管非常方便,但這僅適用於類組件 。
React typedef附帶了一個實用程序,可從任何組件中提取道具的類型。
type ViewProps = React.ComponentProps<typeof View>
type InputProps = React.ComponentProps<'input'>
這有點冗長,但是與類型查找解決方案不同:
所有這些使該解決方案成為最可靠的解決方案:如果您決定從類遷移到掛鈎,則無需重構任何客戶端代碼。
從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 React.ComponentProps
。
從組件中獲取一種屬性
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具有原始類型
給定一個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中 。
這是我如何從組件中獲取道具的解決方案
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”
您可以使用import * as
語法:
import * as MC from './MyComponent';
type Props = MC.Props;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.