diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 02b83fadfcfc20..51f1a54b440c83 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -22,6 +22,7 @@
- `withFocusReturn` HOC: Convert to TypeScript ([#48748](https://github.com/WordPress/gutenberg/pull/48748)).
- `navigateRegions` HOC: Convert to TypeScript ([#48632](https://github.com/WordPress/gutenberg/pull/48632)).
- `withSpokenMessages`: HOC: Convert to TypeScript ([#48163](https://github.com/WordPress/gutenberg/pull/48163)).
+- `withNotices`: HOC: Convert to TypeScript ([#49088](https://github.com/WordPress/gutenberg/pull/49088)).
- `ToolbarButton`: Convert to TypeScript ([#47750](https://github.com/WordPress/gutenberg/pull/47750)).
- `DimensionControl(Experimental)`: Convert to TypeScript ([#47351](https://github.com/WordPress/gutenberg/pull/47351)).
- `PaletteEdit`: Convert to TypeScript ([#47764](https://github.com/WordPress/gutenberg/pull/47764)).
diff --git a/packages/components/src/higher-order/with-notices/README.md b/packages/components/src/higher-order/with-notices/README.md
index 84c484eba101b2..17e1b0e12113b9 100644
--- a/packages/components/src/higher-order/with-notices/README.md
+++ b/packages/components/src/higher-order/with-notices/README.md
@@ -2,7 +2,7 @@
`withNotices` is a React [higher-order component](https://facebook.github.io/react/docs/higher-order-components.html) used typically in adding the ability to post notice messages within the original component.
-Wrapping the original component with `withNotices` encapsulates the component with the additional props `noticeOperations` and `noticeUI`.
+Wrapping the original component with `withNotices` encapsulates the component with the additional props `noticeOperations`, `noticeUI`, and `noticeList`.
**noticeOperations**
Contains a number of useful functions to add notices to your site.
@@ -34,6 +34,9 @@ _Parameters_
#**noticeUi**
The rendered `NoticeList`.
+#**noticeList**
+The array of notice objects to be displayed.
+
## Usage
```jsx
diff --git a/packages/components/src/higher-order/with-notices/index.js b/packages/components/src/higher-order/with-notices/index.js
deleted file mode 100644
index c4057e6b6fff3e..00000000000000
--- a/packages/components/src/higher-order/with-notices/index.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * External dependencies
- */
-import { v4 as uuid } from 'uuid';
-
-/**
- * WordPress dependencies
- */
-import { forwardRef, useState, useMemo } from '@wordpress/element';
-import { createHigherOrderComponent } from '@wordpress/compose';
-
-/**
- * Internal dependencies
- */
-import NoticeList from '../../notice/list';
-
-/**
- * Override the default edit UI to include notices if supported.
- *
- * @param {WPComponent} OriginalComponent Original component.
- *
- * @return {WPComponent} Wrapped component.
- */
-export default createHigherOrderComponent( ( OriginalComponent ) => {
- function Component( props, ref ) {
- const [ noticeList, setNoticeList ] = useState( [] );
-
- const noticeOperations = useMemo( () => {
- /**
- * Function passed down as a prop that adds a new notice.
- *
- * @param {Object} notice Notice to add.
- */
- const createNotice = ( notice ) => {
- const noticeToAdd = notice.id
- ? notice
- : { ...notice, id: uuid() };
- setNoticeList( ( current ) => [ ...current, noticeToAdd ] );
- };
-
- return {
- createNotice,
-
- /**
- * Function passed as a prop that adds a new error notice.
- *
- * @param {string} msg Error message of the notice.
- */
- createErrorNotice: ( msg ) => {
- createNotice( {
- status: 'error',
- content: msg,
- } );
- },
-
- /**
- * Removes a notice by id.
- *
- * @param {string} id Id of the notice to remove.
- */
- removeNotice: ( id ) => {
- setNoticeList( ( current ) =>
- current.filter( ( notice ) => notice.id !== id )
- );
- },
-
- /**
- * Removes all notices
- */
- removeAllNotices: () => {
- setNoticeList( [] );
- },
- };
- }, [] );
-
- const propsOut = {
- ...props,
- noticeList,
- noticeOperations,
- noticeUI: noticeList.length > 0 && (
-
- ),
- };
-
- return isForwardRef ? (
-
- ) : (
-
- );
- }
-
- let isForwardRef;
- const { render } = OriginalComponent;
- // Returns a forwardRef if OriginalComponent appears to be a forwardRef.
- if ( typeof render === 'function' ) {
- isForwardRef = true;
- return forwardRef( Component );
- }
- return Component;
-} );
diff --git a/packages/components/src/higher-order/with-notices/index.tsx b/packages/components/src/higher-order/with-notices/index.tsx
new file mode 100644
index 00000000000000..734fd8b2b1056c
--- /dev/null
+++ b/packages/components/src/higher-order/with-notices/index.tsx
@@ -0,0 +1,116 @@
+/**
+ * External dependencies
+ */
+import { v4 as uuid } from 'uuid';
+
+/**
+ * WordPress dependencies
+ */
+import { forwardRef, useState, useMemo } from '@wordpress/element';
+import { createHigherOrderComponent } from '@wordpress/compose';
+
+/**
+ * Internal dependencies
+ */
+import NoticeList from '../../notice/list';
+import type { WithNoticeProps } from './types';
+
+/**
+ * Override the default edit UI to include notices if supported.
+ *
+ * Wrapping the original component with `withNotices` encapsulates the component
+ * with the additional props `noticeOperations` and `noticeUI`.
+ *
+ * ```jsx
+ * import { withNotices, Button } from '@wordpress/components';
+ *
+ * const MyComponentWithNotices = withNotices(
+ * ( { noticeOperations, noticeUI } ) => {
+ * const addError = () =>
+ * noticeOperations.createErrorNotice( 'Error message' );
+ * return (
+ *
+ * { noticeUI }
+ *
+ *
+ * );
+ * }
+ * );
+ * ```
+ *
+ * @param OriginalComponent Original component.
+ *
+ * @return Wrapped component.
+ */
+export default createHigherOrderComponent( ( OriginalComponent ) => {
+ function Component(
+ props: { [ key: string ]: any },
+ ref: React.ForwardedRef< any >
+ ) {
+ const [ noticeList, setNoticeList ] = useState<
+ WithNoticeProps[ 'noticeList' ]
+ >( [] );
+
+ const noticeOperations = useMemo<
+ WithNoticeProps[ 'noticeOperations' ]
+ >( () => {
+ const createNotice: WithNoticeProps[ 'noticeOperations' ][ 'createNotice' ] =
+ ( notice ) => {
+ const noticeToAdd = notice.id
+ ? notice
+ : { ...notice, id: uuid() };
+ setNoticeList( ( current ) => [ ...current, noticeToAdd ] );
+ };
+
+ return {
+ createNotice,
+ createErrorNotice: ( msg ) => {
+ // @ts-expect-error TODO: Missing `id`, potentially a bug
+ createNotice( {
+ status: 'error',
+ content: msg,
+ } );
+ },
+ removeNotice: ( id ) => {
+ setNoticeList( ( current ) =>
+ current.filter( ( notice ) => notice.id !== id )
+ );
+ },
+ removeAllNotices: () => {
+ setNoticeList( [] );
+ },
+ };
+ }, [] );
+
+ const propsOut = {
+ ...props,
+ noticeList,
+ noticeOperations,
+ noticeUI: noticeList.length > 0 && (
+
+ ),
+ };
+
+ return isForwardRef ? (
+
+ ) : (
+
+ );
+ }
+
+ let isForwardRef: boolean;
+ // @ts-expect-error - `render` will only be present when OriginalComponent was wrapped with forwardRef().
+ const { render } = OriginalComponent;
+ // Returns a forwardRef if OriginalComponent appears to be a forwardRef.
+ if ( typeof render === 'function' ) {
+ isForwardRef = true;
+ return forwardRef( Component );
+ }
+ return Component;
+}, 'withNotices' );
diff --git a/packages/components/src/higher-order/with-notices/test/index.js b/packages/components/src/higher-order/with-notices/test/index.tsx
similarity index 91%
rename from packages/components/src/higher-order/with-notices/test/index.js
rename to packages/components/src/higher-order/with-notices/test/index.tsx
index a403f3c3a80942..cbad7270414e3e 100644
--- a/packages/components/src/higher-order/with-notices/test/index.js
+++ b/packages/components/src/higher-order/with-notices/test/index.tsx
@@ -24,25 +24,30 @@ import {
* Internal dependencies
*/
import withNotices from '..';
+import type { WithNoticeProps } from '../types';
// Implementation detail of Notice component used to query the dismissal button.
const stockDismissText = 'Dismiss this notice';
-function noticesFrom( list ) {
+function noticesFrom( list: string[] ) {
return list.map( ( item ) => ( { id: item, content: item } ) );
}
-function isComponentLike( object ) {
+function isComponentLike( object: any ) {
return typeof object === 'function';
}
-function isForwardRefLike( { render: renderMethod } ) {
+function isForwardRefLike( { render: renderMethod }: any ) {
return typeof renderMethod === 'function';
}
const content = 'Base content';
-const BaseComponent = ( { noticeOperations, noticeUI, notifications } ) => {
+const BaseComponent = ( {
+ noticeOperations,
+ noticeUI,
+ notifications,
+}: WithNoticeProps & { notifications: ReturnType< typeof noticesFrom > } ) => {
useEffect( () => {
if ( notifications ) {
notifications.forEach( ( item ) =>
@@ -78,8 +83,8 @@ describe( 'withNotices return type', () => {
} );
describe( 'withNotices operations', () => {
- let handle;
- const Handle = ( props ) => {
+ let handle: React.MutableRefObject< any >;
+ const Handle = ( props: any ) => {
handle = useRef();
return ;
};
diff --git a/packages/components/src/higher-order/with-notices/types.ts b/packages/components/src/higher-order/with-notices/types.ts
new file mode 100644
index 00000000000000..e914d21d82df7d
--- /dev/null
+++ b/packages/components/src/higher-order/with-notices/types.ts
@@ -0,0 +1,35 @@
+/**
+ * Internal dependencies
+ */
+import type { NoticeListProps } from '../../notice/types';
+
+export type WithNoticeProps = {
+ noticeList: NoticeListProps[ 'notices' ];
+ noticeOperations: {
+ /**
+ * Function passed down as a prop that adds a new notice.
+ *
+ * @param notice Notice to add.
+ */
+ createNotice: (
+ notice: NoticeListProps[ 'notices' ][ number ]
+ ) => void;
+ /**
+ * Function passed as a prop that adds a new error notice.
+ *
+ * @param msg Error message of the notice.
+ */
+ createErrorNotice: ( msg: string ) => void;
+ /**
+ * Removes a notice by id.
+ *
+ * @param id Id of the notice to remove.
+ */
+ removeNotice: ( id: string ) => void;
+ /**
+ * Removes all notices
+ */
+ removeAllNotices: () => void;
+ };
+ noticeUI: false | JSX.Element;
+};
diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json
index aa2434d026ca17..6aaadae65b49cc 100644
--- a/packages/components/tsconfig.json
+++ b/packages/components/tsconfig.json
@@ -45,7 +45,6 @@
"src/**/stories/**/*.js", // only exclude js files, tsx files should be checked
"src/**/test/**/*.js", // only exclude js files, ts{x} files should be checked
"src/index.js",
- "src/duotone-picker",
- "src/higher-order/with-notices"
+ "src/duotone-picker"
]
}