Подтвердить что ты не робот

Значение свойства по умолчанию в компоненте React с помощью TypeScript

Я не могу понять, как установить значения свойств по умолчанию для моих компонентов с помощью 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, которые использует моя компания, полагаются на них и не используют их, не являются выбором.

4b9b3361

Ответ 1

Упор по умолчанию с компонентом класса

Использование 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" } />

Обратите внимание:

  • foo не помечен как необязательный (т.е. foo?: string), даже если он не требуется в качестве атрибута JSX. Пометка как необязательная означает, что это может быть undefined, но на самом деле это никогда не будет undefined, потому что defaultProps предоставляет значение по умолчанию. Подумайте об этом подобно тому, как вы можете пометить параметр функции как необязательный, или значением по умолчанию, но не обоими, но оба означают, что вызову не нужно указывать значение. TypeScript 3. 0+ обрабатывает defaultProps аналогичным образом, что действительно здорово для пользователей React!
  • defaultProps не имеет явной аннотации типа. Его тип выводится и используется компилятором, чтобы определить, какие атрибуты JSX требуются. Вы можете использовать defaultProps: Pick<PageProps, "foo">, чтобы убедиться, что defaultProps соответствует подмножеству PageProps. Подробнее об этом предупреждении объясняется здесь.
  • Для этого требуется @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>
        );
    }
}

Обратите внимание:

  • Хорошей идеей будет аннотировать defaultProps с помощью Partial<>, чтобы он проверял тип по вашим реквизитам, но вам не нужно указывать каждому обязательному свойству значение по умолчанию, что не имеет смысла, поскольку для обязательных свойств никогда не требуется по умолчанию.
  • При использовании strictNullChecks значение this.props.foo будет possibly undefined и потребует ненулевого подтверждения (т.е. this.props.foo!) или защиты типа (т.е. if (this.props.foo) ...), чтобы удалить undefined. Это раздражает, так как значение prop по умолчанию означает, что оно фактически никогда не будет неопределенным, но TS не понимает этот поток. Это одна из главных причин, по которой в TS 3.0 добавлена явная поддержка defaultProps.

До TypeScript 2.1

Это работает так же, но у вас нет типов Partial, поэтому просто опустите Partial<> и либо предоставьте значения по умолчанию для всех требуемых реквизитов (даже если эти значения по умолчанию никогда не будут использоваться), либо полностью пропустите явную аннотацию типов.

Упор по умолчанию с функциональными компонентами

Вы также можете использовать defaultProps на компонентах функций, но вы должны ввести свою функцию в интерфейс FunctionComponent (StatelessComponent в @types/react до версии 16.7.2), чтобы TypeScript знал о defaultProps в функции :

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

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

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

Обратите внимание, что вам не нужно нигде использовать Partial<PageProps>, потому что FunctionComponent.defaultProps уже указан как часть в TS 2. 1+.

Еще одна хорошая альтернатива (это то, что я использую) - это деструктурировать ваши параметры props и напрямую назначить значения по умолчанию:

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

Тогда тебе вообще не нужен defaultProps! Помните, что если вы предоставите defaultProps для компонента функции, он будет иметь приоритет над значениями параметров по умолчанию, поскольку React всегда будет явно передавать значения defaultProps (поэтому параметры никогда не определяются, поэтому параметр по умолчанию никогда не используется. ) Таким образом, вы будете использовать один или другой, а не оба.

Ответ 2

С Typescript 2.1+ используйте Partial <T> вместо того, чтобы сделать ваши свойства интерфейса необязательными.

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

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

Ответ 3

С TypScript 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.6. Он работает с 16.4.11.

Ответ 4

Из комментария @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"
    };

Ответ 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>
    )
  }
}