From 616d2bf8dfe5b7777f17ca240e7ce41dfdb70d33 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Wed, 14 Oct 2020 21:59:49 +0200 Subject: [PATCH 1/2] Type icon component --- packages/components/src/icon/index.js | 50 +++++++++++++++++++++++---- packages/components/tsconfig.json | 1 + 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/packages/components/src/icon/index.js b/packages/components/src/icon/index.js index 225964a2e79aee..43d83ba23bde9b 100644 --- a/packages/components/src/icon/index.js +++ b/packages/components/src/icon/index.js @@ -14,13 +14,39 @@ import { SVG } from '@wordpress/primitives'; */ import Dashicon from '../dashicon'; +/* eslint-disable jsdoc/valid-types */ +/** + * @template T + * @typedef {T extends import('react').ComponentType ? U : T extends string ? import('react').ComponentPropsWithoutRef<'span'> : {}} AdditionalProps + */ +/* eslint-enable jsdoc/valid-types */ + +/** + * @template P + * @typedef {string | import('react').ComponentType

|ReactElement} IconType + */ + +/** + * @template P + * @typedef BaseProps + * + * @property {IconType

|null} icon The icon to render. Supported values are: Dashicons (specified as strings), functions, WPComponent instances and `null`. + * @property {number} [size] The size (width and height) of the icon. + */ + +/** + * @template {{size?: number}} P + * @param {BaseProps

& AdditionalProps>} props + * @return {JSX.Element|null} Element + */ function Icon( { icon = null, size, ...additionalProps } ) { if ( 'string' === typeof icon ) { return ; } - if ( icon && Dashicon === icon.type ) { - return cloneElement( icon, { + // Type Assertion: We know `icon` is defined and we can check the `.type` property. + if ( icon && Dashicon === /** @type {ReactElement} */ ( icon ).type ) { + return cloneElement( /** @type {ReactElement} */ ( icon ), { ...additionalProps, } ); } @@ -29,13 +55,21 @@ function Icon( { icon = null, size, ...additionalProps } ) { const iconSize = size || 24; if ( 'function' === typeof icon ) { if ( icon.prototype instanceof Component ) { - return createElement( icon, { - size: iconSize, - ...additionalProps, - } ); + return createElement( + icon, + /* eslint-disable jsdoc/no-undefined-types */ + /** @type {P} */ ( { + size: iconSize, + ...additionalProps, + } ) + /* eslint-enable jsdoc/no-undefined-types */ + ); } - return icon( { size: iconSize, ...additionalProps } ); + return /** @type {import('react').FunctionComponent} */ ( icon )( { + size: iconSize, + ...additionalProps, + } ); } if ( icon && ( icon.type === 'svg' || icon.type === SVG ) ) { @@ -60,3 +94,5 @@ function Icon( { icon = null, size, ...additionalProps } ) { } export default Icon; + +/** @typedef {import('react').ReactElement} ReactElement */ diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 013aa14f5af344..6e1f78f2cc7650 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -8,6 +8,7 @@ "include": [ "src/base-control/**/*", "src/dashicon/**/*", + "src/icon/**/*", "src/tip/**/*", "src/utils/**/*", "src/visually-hidden/**/*" From 23ca3dc9d0a20e6290431844597e6fb512520dcb Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Fri, 30 Oct 2020 22:40:45 +0100 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Sara Marcondes --- packages/components/src/icon/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/icon/index.js b/packages/components/src/icon/index.js index 43d83ba23bde9b..3c45c65d135e7d 100644 --- a/packages/components/src/icon/index.js +++ b/packages/components/src/icon/index.js @@ -23,21 +23,21 @@ import Dashicon from '../dashicon'; /** * @template P - * @typedef {string | import('react').ComponentType

|ReactElement} IconType + * @typedef {string | import('react').ComponentType

| ReactElement} IconType */ /** * @template P * @typedef BaseProps * - * @property {IconType

|null} icon The icon to render. Supported values are: Dashicons (specified as strings), functions, WPComponent instances and `null`. + * @property {IconType

| null} icon The icon to render. Supported values are: Dashicons (specified as strings), functions, WPComponent instances and `null`. * @property {number} [size] The size (width and height) of the icon. */ /** * @template {{size?: number}} P * @param {BaseProps

& AdditionalProps>} props - * @return {JSX.Element|null} Element + * @return {JSX.Element | null} Element */ function Icon( { icon = null, size, ...additionalProps } ) { if ( 'string' === typeof icon ) {