Дополнительные реквизиты JSX в проекте TSX/JSX

У меня есть проект React, который я конвертирую из JS в TS. Проблема, с которой я сталкиваюсь, заключается в том, что TSX React предполагает, что все свойства, определенные в функциональном компоненте, являются обязательными.

// ComponentA.tsx
class ComponentA extends React.Component<any, any> {
  render() {
    /* Type '{ equalWidth: true; children: Element[]; }' is not assignable to type '{ children: any; className: any; equalWidth: any; }'.
     * Property 'className' is missing in type '{ equalWidth: true; children: Element[]; }'.' */
    return <ComponentB equalWidth />
  }
}

а также

// ComponentB.js
const ComponentB = ({ children, className, equalWidth }) => {
  return (...)
}

Есть ли способ сообщить TS, что все компоненты JSX являются опциональными?

2 ответа

Одним из самых простых вариантов будет установка значения по умолчанию для вашего дополнительного реквизита. В качестве примера, если className необязательно, вы можете изменить свой ComponentB.js что-то вроде этого.

const ComponentB = ({ children, className="", equalWidth }) => {
  return (...)
}

Также, если вы деконструируете свой реквизит в теле функции вместо подписи, TS не будет жаловаться на набор текста.

const ComponentB = (props) => {
  const { children, className, equalWidth } = props;
  return (...)
}

При условии, что ComponentB.js собирается закончить как компонент TypeScript:

interface ComponentBProps {
    children?: ReactNode;
    className?: string;
    equalWidth?: boolean;
}

const ComponentB = ({ children, className, equalWidth }: ComponentBProps) => {
    // 
};

В особом случае, когда все свойства являются необязательными, вы можете удалить ? от каждого свойства интерфейса и использования Partial<ComponentBProps>, но я думаю, что по крайней мере что-то в конечном итоге будет необходимой опорой.


Если вы хотите сохранить ComponentB.js как таковой, то альтернативным решением является создание файла определений типов:

import { ReactNode, StatelessComponent } from "react";

interface ComponentBProps {
    children?: ReactNode
    className?: string;
    equalWidth?: boolean;
}

export const ComponentB: StatelessComponent<ComponentBProps>;

Если вы поместите в тот же каталог, что и файл JavaScript, и имя ComponentB.d.tsтогда вы сможете импортировать ComponentB в вашем файле TypeScript.

То, как я написал определение, предполагает, что компонент является именованным экспортом, а не по умолчанию, т.е. он экспортируется как export const ComponentB в .js файл.

(вероятно) рабочий пример: https://github.com/fenech/tsx-jsx

Другие вопросы по тегам