带有 forwardRef typescript的 JSX 点符号

IT技术 reactjs typescript
2021-05-05 08:00:53

我正在尝试使用 forwardRef 找出 Dot Notation 组件的类型。

所以我发现这个例子完美地说明了我目前如何使用点表示法,但不包括 forwardRef:https ://codesandbox.io/s/stpkm

这就是我想要实现的目标,但无法弄清楚类型。

import { forwardRef, useImperativeHandle } from "react";
//
import { ForwardRefRenderFunction } from "react";

const TabToggle: React.FC = () => null;
const TabContent: React.FC = () => null;

interface TabsStatic {
  Toggle: typeof TabToggle;
  Content: typeof TabContent;
}

export interface TabsProps {
  initialIndex?: number;
}

export interface TabsRefMethods {
  show: () => null;
  hide: () => null;
}

export const Tabs: React.ForwardRefRenderFunction<
  TabsRefMethods,
  TabsProps & TabsStatic
> = forwardRef((props, ref) => {
  const openFn = () => null;
  const closeFn = () => null;
  useImperativeHandle(ref, () => ({ show: openFn, hide: closeFn }));
  return null;
});

Tabs.Toggle = TabToggle;
Tabs.Content = TabContent;

代码沙盒演示https : //codesandbox.io/s/jsx-dot-notation-in-typescript-with-react-forked-38e1z? file =/ src / Tabs.tsx

2个回答

我知道并使用过两种可能的方法。两者的权衡略有不同。

首先是&将静态组件插入 ( ) 并将它们标记为可选 ( Partial) 以便在声明组件时不会出错。缺点是它们被表示为可选,即使它们总是被设置。

import * as React from "react";

const TabToggle: React.FC = () => null;
const TabContent: React.FC = () => null;

interface TabsStatic {
  Toggle: typeof TabToggle;
  Content: typeof TabContent;
}

export interface TabsProps {
  initialIndex?: number;
}

export interface TabsRefMethods {
  show: () => null;
  hide: () => null;
}

export const Tabs: React.ForwardRefExoticComponent<
  React.PropsWithoutRef<TabsProps> & React.RefAttributes<TabsRefMethods>
> &
  Partial<TabsStatic> = React.forwardRef((props, ref) => null);

Tabs.Toggle = TabToggle;
Tabs.Content = TabContent;

另一种方法是让它们成为必需,但这需要演员阵容。结果类型更准确,但它确实需要强制转换。

type TabsComponent = React.ForwardRefExoticComponent<
  React.PropsWithoutRef<TabsProps> & React.RefAttributes<TabsRefMethods>
> &
  TabsStatic;

export const Tabs = React.forwardRef((props, ref) => null) as TabsComponent;

Tabs.Toggle = TabToggle;
Tabs.Content = TabContent;

有更简单的方法可以达到相同的结果:

const Flex = React.forwardRef(function Flex(...) {
  ...
})

const FlexRow = React.forwardRef(...)
const FlexColumn = React.forwardRef(...)

const FlexNamespace = Object.assign(Flex, {Row: FlexRow, Column: FlexColumn})

export {FlexNamespace as Flex}

现在您可以使用Flex, Flex.Row, 并且Flex.ColumnTS 很高兴。神奇的线是Object.assign它不会导致相同的类型问题Flex.Row = FlexRow别问我为什么,我只是不小心发现了这个😄