19

我有一个要从 JS 转换为 TS 的 React 项目。我遇到的一个问题是 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 组件道具都是可选的?

4

2 回答 2

10

一个最简单的选项是为您的可选道具设置默认值。例如,如果className是可选的,您可以将您的更改ComponentB.js为类似的内容。

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

此外,如果您在函数体而不是签名中解构道具,则 TS 不会抱怨打字。

const ComponentB = (props) => {
  const { children, className, equalWidth } = props;
  return (...)
}
于 2017-08-25T00:58:23.963 回答
8

假设这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,而不是默认的,即它像export const ComponentB.js文件中一样被导出。

(可能)工作示例:https ://github.com/fenech/tsx-jsx

于 2017-07-31T16:29:13.297 回答