Как использовать PropTypes.shape с Typescript

Я выполняю рефакторинг приложения React с Javascript на Typescript, но у меня возникают проблемы с переносом, особенно shape PropType. Мой код сейчас выглядит так:

import React from 'react';
import PropTypes from 'prop-types';

interface FooterProps {
  labels: FooterLabels;
}

interface FooterLabels {
  body: string;
}

const Footer: React.FC<FooterProps> = ({ labels }) => (
  <div className="footer">
    {/* ... */}
  </div>
);

Footer.propTypes = {
  labels: PropTypes.shape({
    body: PropTypes.string.isRequired
  }).isRequired
};

export default Footer;

Но я получаю сообщение об ошибке в PropTypes:

Type 'Validator<InferProps<{ body: Validator<string>; }>>' is not assignable to type 'Validator<FooterLabels>'.
  Type 'InferProps<{ body: Validator<string>; }>' is not assignable to type 'FooterLabels'.
    Property 'body' is optional in type 'InferProps<{ body: Validator<string>; }>' but required in type 'FooterLabels'.ts(2322)
FooterAppPromo.tsx(5, 3): The expected type comes from property 'labels' which is declared here on type 'WeakValidationMap<FooterProps>'

Я новичок в Typescript, поэтому иногда я действительно не знаю, что делаю, но я пытался делать такие вещи, как:

Footer.propTypes = {
  labels: PropTypes.shape<FooterLabels>({
    body: PropTypes.string.isRequired
  }).isRequired
};

Но я получаю ошибки. Я попытался найти примеры реализации, но не нашел.

РЕДАКТИРОВАТЬ

Типы машинописных текстов и PropTypes не одно и то же. Вы можете легко написать пример, в котором проверка Typescript проходит, но вы все равно получаете предупреждение PropTypes (например, внешний API, который возвращает число, где должна быть строка). Вот две статьи, объясняющие, почему:

Итак, мой вопрос: как заставить вложенные объекты PropTypes (PropTypes.shape() или, может быть, PropTypes.objectOf()) работать с TypeScript?


person Thiago Loddi    schedule 11.12.2019    source источник
comment
Думаю, хватит только interface и React.FC<FooterProps>. Вам не нужно propTypes в React with Typescript   -  person Quoc-Anh Nguyen    schedule 11.12.2019
comment
@AnhNguyen Я бы сказал, что если вы это сделаете, можно будет использовать только TS-осведомленного потребителя вашего компонента. Тоже ищу решение в TS с propTypes. Прямо сейчас tsc ошибки: Type 'undefined' is not assignable to type 'MetaType'.   -  person Danosaure    schedule 05.03.2020


Ответы (3)


Ошибка PropTypes возникает из-за того, что вы пытаетесь использовать PropType.shape, фигура позволяет вам иметь дополнительные значения в вашей фигуре, и в этом случае ваш интерфейс является строгим, что означает, что у вас нет какого-либо дополнительного значения, а React.Validator - это пытаясь вывести ваши типы за вашими интерфейсами, и это вызывает ошибку.

Проще говоря, если у вас строгий интерфейс с необязательными значениями, вместо использования PropType.shape вы должны использовать PropType.exact, и это должно предотвратить ошибку.

E.G:

Footer.propTypes = {
  labels: PropTypes.exact({
    body: PropTypes.string
  }).isRequired
};

По этой причине в вашем сообщении об ошибке появляется

Свойство body не является обязательным для типа InferProps ‹{body: Validator; } ›', Но требуется в типе' FooterLabels'.ts (2322)

ИЗМЕНЕНО

Это происходит только потому, что вы используете компонент const Footer: React.FC<FooterProps> = ({ labels }) => (

FC (FunctionComponent Interface), изучающий интерфейсы, представлен как

interface FunctionComponent<P = {}> {
        (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
        propTypes?: WeakValidationMap<P>;
        contextTypes?: ValidationMap<any>;
        defaultProps?: Partial<P>;
        displayName?: string;
    }

Строка, которую мы должны здесь выделить, - это propTypes?: WeakValidationMap<P>; Это та, которая определяет наши типы на основе наших PropTypes.

У вас есть второй вариант использования типов в React, но я не рекомендую его, вместо использования FC вы можете использовать тип ReactNode, но вы потеряете выводы, которые у вас есть при выводе типа интерфейса FC.

E.G. function Footer = ({ labels }:FooterProps): ReactNode => (

person Nicolás Juárez Nuño    schedule 02.08.2020

На самом деле вам не нужно propTypes здесь - labels имеет только одно вложенное поле body, которое имеет тип FooterLabels.

interface FooterProps {
  labels: {
     body: FooterLabels;
  };
}
person kind user    schedule 11.12.2019

person    schedule
comment
Пожалуйста, не публикуйте только код в качестве ответа, но также объясните, что делает ваш код и как он решает проблему вопроса. Ответы с объяснением обычно более качественные и с большей вероятностью получат положительные отзывы. - person Mark Rotteveel; 09.04.2020