Типизация пропсов React TypeScript: ?: vs | undefined

    При разработке React-компонентов на TypeScript часто возникает вопрос: как правильно объявить необязательный проп - через prop?: Type или через prop: Type | undefined? На первый взгляд разница невелика, но на практике выбор влияет на читаемость кода, поведение IDE и обязательность передачи аргумента. Разберём оба подхода и определим, какой из них считается production-grade.

    Синтаксис prop?: Type

    Запись prop?: Type означает, что проп является необязательным. Компонент можно использовать без передачи этого свойства. Если же проп передан, он должен строго соответствовать типу Type. При этом внутри компонента значение пропа может быть undefined, если его не передали.

    interface Props {
      name?: string;
    }
    
    const Greeting: React.FC<Props> = ({ name }) => {
      return <h1>Привет, {name ?? 'гость'}</h1>;
    };
    
    // Использование:
    <Greeting />              // OK, name = undefined
    <Greeting name="Анна" /> // OK
    <Greeting name={undefined} /> // OK, но обычно избыточно
    

    Синтаксис prop: Type | undefined

    Запись prop: Type | undefined делает проп обязательным для передачи, но допускает значение undefined. Компонент всегда ожидает этот атрибут, даже если его значение - undefined.

    interface Props {
      name: string | undefined;
    }
    
    const Greeting: React.FC<Props> = ({ name }) => {
      return <h1>Привет, {name ?? 'гость'}</h1>;
    };
    
    // Использование:
    <Greeting />              // Ошибка TypeScript! Проп обязателен
    <Greeting name="Анна" /> // OK
    <Greeting name={undefined} /> // OK
    

    Когда что выбирать?

    prop?: Type - для действительно необязательных свойств

    Используйте ?:, когда проп может отсутствовать по логике компонента. Например, className, style, onClick - их часто не передают. Это стандартный способ сделать свойство опциональным.

    prop: Type | undefined - для обязательных, но временно undefined

    Этот подход применяется, когда проп критически важен для работы компонента, но на этапе инициализации его значение ещё не определено. Например, данные, загружаемые с сервера, или стейт, который появляется после монтирования. Компонент должен явно получить проп, даже если он пока undefined.

    Лучшие практики (production-grade)

    • Отдавайте предпочтение ?: для необязательных пропов - это короче, понятнее и соответствует общепринятому стилю React.
    • Используйте Type | undefined только когда нужна обязательная передача, например, для пропов, которые влияют на ключевое поведение компонента.
    • Не смешивайте оба подхода в одной интерфейсе без необходимости - это запутывает читателя.
    • Для временно undefined значений внутри компонента применяйте проверки типа ?? или typeof, а не меняйте сигнатуру пропа.

    Частые ошибки и нюансы

    Одна из распространённых ошибок - использовать prop: Type | undefined для всех необязательных полей, думая, что это «более строго». На самом деле это вынуждает разработчика всегда передавать проп, что ухудшает читаемость и нарушает привычный UX React-компонентов. Инструменты статического анализа (ESLint, Prettier) часто рекомендуют именно ?: как более лаконичный вариант.

    Также помните: если проп объявлен как prop?: Type, то его тип внутри компонента - Type | undefined. Разница только в обязательности передачи на стороне родителя.

    В крупных проектах (например, в коде библиотек вроде Material-UI или Ant Design) используется именно ?: для опциональных свойств. Это де-факто стандарт.

    Часто задаваемые вопросы