TypeScript를 사용하는 React 컴포넌트의 기본 특성 값


153

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맞다. 그 코드를 게시 할 수 있습니까?
Aaron Beall

답변:


327

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

사용 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(매개 변수가 정의되지 않습니다 때문에, 따라서 기본 매개 변수가 사용되지 않습니다.) 당신이 사용하는 거라고 그래서 값을 둘 다가 아닌 둘 중 하나입니다.


2
소품 <PageComponent>을 전달하지 않고 어딘가에서 사용하는 것처럼 오류가 발생합니다 foo. foo?: string인터페이스에서 사용하여 옵션으로 만들 수 있습니다 .
Aaron Beall

1
@Aaron 그러나 defaultProps가 PageProps 인터페이스를 구현하지 않기 때문에 tsc는 컴파일 오류를 발생시킵니다. 모든 인터페이스 속성을 선택적으로 (나쁜) 만들거나 모든 필수 필드 (필요한 상용구)에 대해 기본값을 지정하거나 defaultProps에 유형을 지정하지 않아야합니다.
pamelus

1
@adrianmoisa 당신은 기본 소품을 의미합니까? 예, 작동하지만 구문이 다릅니다 ... 컴퓨터로 돌아올 때 대답에 예를 추가하겠습니다 ...
Aaron Beall

1
@AdrianMoisa s 함수 구성 요소 예제로 업데이트
Aaron Beall

1
@Jared 예, 모든 (컴파일러 및 React 런타임)이 제대로 작동하려면 public static defaultProps또는 static defaultProps( public기본값) 이어야 합니다. 그것은과 런타임에 작동 할 수 private static defaultProps때문 만 private하고 public런타임에 존재하지 않지만, 컴파일러가 제대로 작동하지 않을 것입니다.
Aaron Beall

18

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

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

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

6

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.


좋은 답변입니다! 처리 방법 : export interface Props { name?: string;}name은 선택적인 prop입니까? 계속 받고 있습니다TS2532 Object is possibly 'undefined'
Fydo

@Fydo 옵션 소품의 기본값을 가질 필요는 없습니다. 왜냐하면 소품 undefined의 자동 기본값 이기 때문 입니다. undefined때로는 명시 적 값으로 전달할 수 있지만 다른 기본값이 있습니까? export interface Props {name: string | undefined;}대신 사용해 보셨습니까 ? 그것을 시도하지 않고 단지 아이디어.
CorayThan

추가 ?는 추가 와 동일합니다 |undefined. 선택적으로 소품을 전달하고 defaultProps해당 사례를 처리 하고 싶습니다 . TS3에서는 아직 불가능한 것 같습니다. 난 그냥 무서워 사용합니다 name!나는 그것이 결코 알고 있기 때문에 구문을 undefineddefaultProps설정됩니다. 어쨌든 고마워!
Fydo

1
이것이 정답이기 때문에 공감되었습니다! 또한이 새로운 기능과 약간 더 자세한 설명으로 받아 들인 대답 (역사 책이되기 시작했습니다)을 업데이트했습니다. :)
Aaron Beall

5

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

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

3

허용 된 답변에 대한 @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"
    };

0

기능적 구성 요소의 경우 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;

0

기능성 구성 요소

실제로 기능적 구성 요소의 모범 사례는 다음과 같습니다. 샘플 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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.