From c53e208255b398de27143466314c7be56cf516c1 Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Sun, 25 Dec 2022 13:53:29 +0800 Subject: [PATCH] refactor: improve typing in RadioGroup component (#2722) --- .../src/components/RadioGroup/index.tsx | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/console/src/components/RadioGroup/index.tsx b/packages/console/src/components/RadioGroup/index.tsx index cd5209316..aa3530504 100644 --- a/packages/console/src/components/RadioGroup/index.tsx +++ b/packages/console/src/components/RadioGroup/index.tsx @@ -1,14 +1,23 @@ +import type { Falsy, Nullable } from '@silverhand/essentials'; import classNames from 'classnames'; -import type { LegacyRef, ReactNode } from 'react'; +import type { JSXElementConstructor, Key, Ref } from 'react'; import { Children, cloneElement, forwardRef, isValidElement } from 'react'; import type { Props as RadioProps } from './Radio'; import Radio from './Radio'; import * as styles from './index.module.scss'; +type RadioElement = + | { + type: JSXElementConstructor; + props: RadioProps; + key: Nullable; + } + | Falsy; + type Props = { name: string; - children: ReactNode; + children: RadioElement | RadioElement[]; value?: string; type?: 'card' | 'plain'; className?: string; @@ -17,17 +26,24 @@ type Props = { const RadioGroup = ( { name, children, value, className, onChange, type = 'plain' }: Props, - reference?: LegacyRef + ref?: Ref ) => { return ( -
+
{Children.map(children, (child) => { - if (!isValidElement(child) || child.type !== Radio) { - return child; + if (!child || !isValidElement(child) || child.type !== Radio) { + // As typescript still cannot restrict React children to specific component types, we need to alert the error in runtime. + // Reference: https://github.com/microsoft/TypeScript/issues/21699 + console.error( + 'Invalid child type for RadioGroup:', + child ? child.type : child, + '. Expecting Radio components.' + ); + + // Do not render child if not a valid Radio component + return null; } - // FIXME: @Charles - // @ts-expect-error to be fixed return cloneElement(child, { name, isChecked: value === child.props.value,