[reactjs] 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 구성 요소는이 구성 요소에 의존하므로 사용하지 않는 것이 좋습니다.



답변

클래스 컴포넌트가있는 기본 소품

사용 static defaultProps이 정확합니다. props 및 state에 클래스가 아닌 인터페이스를 사용해야합니다.

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" } />

참고 :

TypeScript 2.1에서 3.0까지

TypeScript 3.0이 컴파일러 지원을 구현하기 전에는 defaultProps계속해서이를 사용할 수 있었고 런타임에 React에서 100 % 작동했습니다. 그러나 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및 null이 아닌 주장 (즉 필요 this.props.foo!) 또는 유형 가드 (예를 if (this.props.foo) ...제거하기 위해) undefined. 기본 소품 값은 실제로 정의되지 않을 것이므로 TS는이 흐름을 이해하지 못했기 때문에 성가신 일입니다. 이것이 TS 3.0이에 대한 명시적인 지원을 추가 한 주요 이유 중 하나입니다 defaultProps.

TypeScript 2.1 이전

이것은 동일하게 작동하지만 Partial유형이 없으므로 Partial<>모든 필수 소품에 대해 기본값을 생략 하거나 제공하거나 (기본값은 사용되지 않더라도) 명시 적 유형 주석을 완전히 생략하십시오.

기능적 구성 요소가있는 기본 소품

defaultProps함수 구성 요소에서도 사용할 수 있지만 TypeScript가 함수 에 대해 알 수 있도록 FunctionComponent( 이전 버전 ) 인터페이스 StatelessComponent에 함수를 입력해야 합니다.@types/react16.7.2defaultProps

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

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

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

TS 2.1 이상에서는 이미 부분적으로 지정되어 있으므로 Partial<PageProps>어디에서나 사용할 필요가 없습니다 FunctionComponent.defaultProps.

또 다른 좋은 대안 (이것이 내가 사용하는 것)은 props매개 변수를 구성 해제하고 기본값을 직접 할당하는 것입니다.

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

그럼 당신은 전혀 필요하지 않습니다 defaultProps! 당신이 경우주의하십시오 않는 제공 defaultProps항상 명시 적으로 전달합니다 반작용 때문에, 함수의 구성 요소가 기본 매개 변수 값보다 우선합니다 defaultProps(매개 변수가 정의되지 않습니다 때문에, 따라서 기본 매개 변수가 사용되지 않습니다.) 당신이 사용하는 거라고 그래서 값을 둘 다가 아닌 둘 중 하나입니다.


답변

Typescript 2.1 이상에서는 인터페이스 속성을 옵션으로 만드는 대신 Partial <T>를 사용하십시오.

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

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


답변

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.


답변

기본값이 필요한 옵션 소품이있는 경우. 여기에 신용 🙂

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>
    )
  }
}


답변

허용 된 답변에 대한 @pamelus의 의견 :

모든 인터페이스 속성을 선택적으로 (나쁜) 만들거나 모든 필수 필드 (필요한 상용구)에 대해 기본값을 지정하거나 defaultProps에 유형을 지정하지 않아야합니다.

실제로 Typescript의 인터페이스 상속을 사용할 수 있습니다 . 결과 코드는 조금 더 장황합니다.

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"
    };


답변

기능적 구성 요소의 경우 props인수를 유지하기 위해 내 해결책은 다음과 같습니다.

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

// IMPORTANT!, defaultProps is of type {bar: number} rather than Partial<Props>!
const defaultProps = {
  bar: 1
}


// externalProps is of type Props
const FooComponent = exposedProps => {
  // props works like type Required<Props> now!
  const props = Object.assign(defaultProps, exposedProps);

  return ...
}

FooComponent.defaultProps = defaultProps;


답변

기능성 구성 요소

실제로 기능적 구성 요소의 모범 사례는 다음과 같습니다. 샘플 Spinner 구성 요소를 만듭니다.

import React from 'react';
import { ActivityIndicator } from 'react-native';
import { colors } from 'helpers/theme';
import type { FC } from 'types';

interface SpinnerProps {
  color?: string;
  size?: 'small' | 'large' | 1 | 0;
  animating?: boolean;
  hidesWhenStopped?: boolean;
}

const Spinner: FC<SpinnerProps> = ({
  color,
  size,
  animating,
  hidesWhenStopped,
}) => (
  <ActivityIndicator
    color={color}
    size={size}
    animating={animating}
    hidesWhenStopped={hidesWhenStopped}
  />
);

Spinner.defaultProps = {
  animating: true,
  color: colors.primary,
  hidesWhenStopped: true,
  size: 'small',
};

export default Spinner;