web-dev-qa-db-ja.com

TypeScriptを使用したReactコンポーネントのデフォルトプロパティ値

TypeScriptを使用して自分のコンポーネントにデフォルトのプロパティ値を設定する方法がわかりません。

これがソースコードです。

class PageState
{
}

export class PageProps
{
    foo: string = "bar";
}

export class PageComponent extends React.Component<PageProps, PageState>
{
    public render(): JSX.Element
    {
        return (
            <span>Hello, world</span>
        );
    }
}

そして私がこのようなコンポーネントを使おうとすると:

ReactDOM.render(<PageComponent />, document.getElementById("page"));

プロパティfooが見つからないというエラーが表示されます。デフォルト値を使いたいのですが。私はまたコンポーネントの中でstatic defaultProps = ...を使用しようとしました、しかし私が疑ったようにそれは効果がありませんでした。

src/TypeScript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.

既定のプロパティ値を使用する方法私の会社が使用しているJSコンポーネントの多くはそれらに依存しており、それらを使用しないことは選択の余地がありません。

105
Tom

クラスコンポーネントを含むデフォルトの小道具

static defaultPropsを使用することは正しいです。小道具と状態のために、クラスではなくインタフェースも使うべきです。

更新2018/12/1:TypeScriptにより型が改善されました - defaultPropsに関連するチェックは時間の経過とともに変わります。古い使用法や問題に至るまでの最新かつ最大の使用法についてお読みください

TypeScript 3.0以上の場合

TypeScript特に defaultPropsのサポートが追加されました 型チェックが期待どおりに機能するようにします。例:

interface PageProps {
  foo: string;
  bar: string;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, { this.props.foo.toUpperCase() }</span>
        );
    }
}

これは、foo属性を渡さずにレンダリングおよびコンパイルできます。

<PageComponent bar={ "hello" } />

ご了承ください:

  • JSX属性として必須ではありませんが、fooはオプション(つまりfoo?: string)としてnotとマークされていません。オプションとしてマークすることはそれがundefinedであることを意味しますが、実際にはundefinedはデフォルト値を提供するので決して実際にはdefaultPropsになることはありません。それはどのように似ていると考えてください あなたはオプションとして、またはデフォルト値で、関数パラメータをマークすることができます、しかし両方ともコールが値を指定する必要がないことを意味します 。 TypeScript 3.0以降ではdefaultPropsも同じように扱われます。これはReactユーザーにとっては本当に素晴らしいことです。
  • defaultPropsには明示的な型注釈はありません。その型は、どのJSX属性が必要かを判断するために、コンパイラによって推測され使用されます。 defaultPropsPagePropsのサブセットと確実に一致させるためにdefaultProps: Pick<PageProps, "foo">を使用できます。この警告に関する詳細は ここで説明 です。
  • これが正しく動作するには@types/reactバージョン16.4.11が必要です。

TypeScript 2.1から3.0まで

TypeScript 3.0がdefaultPropsのコンパイラサポートを実装する前は、まだそれを利用することができ、実行時には100%Reactで動作していましたが、TypeScriptはJSX属性をチェックするときに小道具しか考慮しなかったので?。例:

interface PageProps {
    foo?: string;
    bar: number;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps: Partial<PageProps> = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, world</span>
        );
    }
}

ご了承ください:

  • defaultPropsPartial<>をアノテーションしてあなたの小道具に対して型チェックするようにすることをお勧めしますが、必要なすべてのプロパティにデフォルト値を指定する必要はありません。
  • strictNullChecksを使用する場合、this.props.fooの値はpossibly undefinedとなり、undefinedを削除するにはnull以外のアサーション(つまりthis.props.foo!)またはタイプガード(すなわちif (this.props.foo) ...)が必要になります。デフォルトのprop値が実際には未定義になることはないことを意味するので、これは厄介です。しかしTSはこのフローを理解していませんでした。これが、TS 3.0がdefaultPropsの明示的なサポートを追加した主な理由の1つです。

TypeScript 2.1より前

これは同じように機能しますが、Partial型はありませんので、Partial<>を省略し、必要なすべての小道具にデフォルト値を指定するか、明示的な型注釈を完全に省略します。

機能部品 のデフォルトの小道具

関数コンポーネントにもdefaultPropsを使用できますが、TypeScriptが関数のStatelessComponentを認識できるように、FunctionComponent@types/react version 16.7.2 +のdefaultProps)インタフェースに関数を入力する必要があります。

interface PageProps {
  foo?: string;
  bar: number;
}

const PageComponent: StatelessComponent<PageProps> = (props) => {
  return (
    <span>Hello, {props.foo}, {props.bar}</span>
  );
};

PageComponent.defaultProps = {
  foo: "default"
};

Partial<PageProps>はTS 2.1+ではすでにパーシャルとして指定されているので、どこにでもStatelessComponent.defaultPropsを使用する必要はありません。

もう一つのいい方法(これは私が使っているものです)はあなたのpropsパラメータを分解してデフォルト値を直接割り当てることです:

const PageComponent: StatelessComponent<PageProps> = ({foo = "default", bar}) => {
  return (
    <span>Hello, {foo}, {bar}</span>
  );
};

それならdefaultPropsはまったく必要ありません。 Reactは常にdefaultPropsの値を明示的に渡すので、関数コンポーネントでdoを指定すると(defaultPropsを指定した場合は優先されます。したがって、デフォルトのパラメータは使用されません。)両方を使用するのではなく、どちらか一方を使用します。

235
Aaron Beall

TypeScript 2.1以降では、インターフェイスプロパティをオプションにする代わりにPartial <T>を使用してください。

export interface Props {
    obj: Model,
    a: boolean
    b: boolean
}

public static defaultProps: Partial<Props> = {
    a: true
};
16
Learner

TypeScript 3.0では、この問題に対して 新しい解決策 があります。

export interface Props {
    name: string;
}

export class Greet extends React.Component<Props> {
    render() {
        const { name } = this.props;
        return <div>Hello ${name.toUpperCase()}!</div>;
    }
    static defaultProps = { name: "world"};
}

// Type-checks! No type assertions needed!
let el = <Greet />

これがうまくいくためには@types/reactより新しいバージョンの16.4.6が必要であることに注意してください。 16.4.11で動作します。

5
CorayThan

受け入れられた答えの@pamelusによるコメントから:

すべてのインターフェースプロパティをオプション(無効)にするか、すべての必須フィールドにもデフォルト値を指定する(不要な定型句)か、defaultPropsにtypeを指定しないようにする必要があります。

実際にはTypeScriptの interface inheritance を使うことができます。結果のコードはもう少し冗長です。

interface OptionalGoogleAdsProps {
    format?: string;
    className?: string;
    style?: any;
    scriptSrc?: string
}

interface GoogleAdsProps extends OptionalGoogleAdsProps {
    client: string;
    slot: string;
}


/**
 * Inspired by https://github.com/wonism/react-google-ads/blob/master/src/google-ads.js
 */
export default class GoogleAds extends React.Component<GoogleAdsProps, void> {
    public static defaultProps: OptionalGoogleAdsProps = {
        format: "auto",
        style: { display: 'block' },
        scriptSrc: "//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"
    };
3

デフォルト値を必要とするオプションの小道具を持っている人のために。 ここでクレジット:)

interface Props {
  firstName: string;
  lastName?: string;
}

interface DefaultProps {
  lastName: string;
}

type PropsWithDefaults = Props & DefaultProps;

export class User extends React.Component<Props> {
  public static defaultProps: DefaultProps = {
    lastName: 'None',
  }

  public render () {
    const { firstName, lastName } = this.props as PropsWithDefaults;

    return (
      <div>{firstName} {lastName}</div>
    )
  }
}
1
Morlo Mbakop