diff --git a/packages/compose/README.md b/packages/compose/README.md
index 674eb97b5c6b46..734dbee0454059 100644
--- a/packages/compose/README.md
+++ b/packages/compose/README.md
@@ -81,25 +81,35 @@ name, returns the enhanced component augmented with a generated displayName.
_Parameters_
-- _mapComponentToEnhancedComponent_ `Function`: Function mapping component to enhanced component.
+- _mapComponentToEnhancedComponent_ `( OriginalComponent: ComponentType< TProps > ) => ComponentType< Subtract< TProps, TObviatedProps > >`: Function mapping component to enhanced component.
- _modifierName_ `string`: Seed name from which to generated display name.
_Returns_
-- `WPComponent`: Component class with generated display name assigned.
+- `HigherOrderComponent< TObviatedProps >`: Component class with generated display name assigned.
# **ifCondition**
Higher-order component creator, creating a new component which renders if
the given condition is satisfied or with the given optional prop name.
+_Usage_
+
+```ts
+type Props = { foo: string };
+const Component = ( props: Props ) =>
{ props.foo }
;
+const ConditionalComponent = ifCondition( ( props: Props ) => props.foo.length !== 0 )( Component );
+; // => null
+; // => bar
;
+```
+
_Parameters_
-- _predicate_ `Function`: Function to test condition.
+- _predicate_ `( props: TProps ) => boolean`: Function to test condition.
_Returns_
-- `Function`: Higher-order component.
+- `HigherOrderComponent`: Higher-order component.
# **pure**
diff --git a/packages/compose/src/higher-order/if-condition/index.js b/packages/compose/src/higher-order/if-condition/index.js
deleted file mode 100644
index b0596729b7a362..00000000000000
--- a/packages/compose/src/higher-order/if-condition/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * Internal dependencies
- */
-import createHigherOrderComponent from '../../utils/create-higher-order-component';
-
-/**
- * Higher-order component creator, creating a new component which renders if
- * the given condition is satisfied or with the given optional prop name.
- *
- * @param {Function} predicate Function to test condition.
- *
- * @return {Function} Higher-order component.
- */
-const ifCondition = ( predicate ) =>
- createHigherOrderComponent(
- ( WrappedComponent ) => ( props ) => {
- if ( ! predicate( props ) ) {
- return null;
- }
-
- return ;
- },
- 'ifCondition'
- );
-
-export default ifCondition;
diff --git a/packages/compose/src/higher-order/if-condition/index.tsx b/packages/compose/src/higher-order/if-condition/index.tsx
new file mode 100644
index 00000000000000..478635f6b1ec6c
--- /dev/null
+++ b/packages/compose/src/higher-order/if-condition/index.tsx
@@ -0,0 +1,39 @@
+/**
+ * Internal dependencies
+ */
+import createHigherOrderComponent from '../../utils/create-higher-order-component';
+// eslint-disable-next-line no-duplicate-imports
+import type { HigherOrderComponent } from '../../utils/create-higher-order-component';
+
+/**
+ * Higher-order component creator, creating a new component which renders if
+ * the given condition is satisfied or with the given optional prop name.
+ *
+ * @example
+ * ```ts
+ * type Props = { foo: string };
+ * const Component = ( props: Props ) => { props.foo }
;
+ * const ConditionalComponent = ifCondition( ( props: Props ) => props.foo.length !== 0 )( Component );
+ * ; // => null
+ * ; // => bar
;
+ * ```
+ *
+ * @param predicate Function to test condition.
+ *
+ * @return Higher-order component.
+ */
+const ifCondition = < TProps, >(
+ predicate: ( props: TProps ) => boolean
+): HigherOrderComponent =>
+ createHigherOrderComponent< {}, TProps >(
+ ( WrappedComponent ) => ( props: TProps ) => {
+ if ( ! predicate( props ) ) {
+ return null;
+ }
+
+ return ;
+ },
+ 'ifCondition'
+ );
+
+export default ifCondition;
diff --git a/packages/compose/src/utils/create-higher-order-component/index.js b/packages/compose/src/utils/create-higher-order-component/index.js
deleted file mode 100644
index 7366fb0c3e06fe..00000000000000
--- a/packages/compose/src/utils/create-higher-order-component/index.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * External dependencies
- */
-import { camelCase, upperFirst } from 'lodash';
-
-/**
- * Given a function mapping a component to an enhanced component and modifier
- * name, returns the enhanced component augmented with a generated displayName.
- *
- * @param {Function} mapComponentToEnhancedComponent Function mapping component
- * to enhanced component.
- * @param {string} modifierName Seed name from which to
- * generated display name.
- *
- * @return {WPComponent} Component class with generated display name assigned.
- */
-function createHigherOrderComponent(
- mapComponentToEnhancedComponent,
- modifierName
-) {
- return ( OriginalComponent ) => {
- const EnhancedComponent = mapComponentToEnhancedComponent(
- OriginalComponent
- );
- const {
- displayName = OriginalComponent.name || 'Component',
- } = OriginalComponent;
- EnhancedComponent.displayName = `${ upperFirst(
- camelCase( modifierName )
- ) }(${ displayName })`;
-
- return EnhancedComponent;
- };
-}
-
-export default createHigherOrderComponent;
diff --git a/packages/compose/src/utils/create-higher-order-component/index.ts b/packages/compose/src/utils/create-higher-order-component/index.ts
new file mode 100644
index 00000000000000..a55ce84ea4a4c8
--- /dev/null
+++ b/packages/compose/src/utils/create-higher-order-component/index.ts
@@ -0,0 +1,58 @@
+/**
+ * External dependencies
+ */
+import { camelCase, upperFirst } from 'lodash';
+// eslint-disable-next-line no-restricted-imports
+import type { ComponentType } from 'react';
+import type { Subtract } from 'utility-types';
+
+/**
+ * Higher order components can cause props to be obviated. For example a HOC that
+ * injects i18n props will obviate the need for the i18n props to be passed to the component.
+ *
+ * If a HOC does not obviate the need for any specific props then we default to `{}` which
+ * essentially subtracts 0 from the original props of the passed in component. An example
+ * of this is the `pure` HOC which does not change the API surface of the component but
+ * simply modifies the internals.
+ */
+export interface HigherOrderComponent< TObviatedProps extends object = {} > {
+ < TP extends TObviatedProps >(
+ OriginalComponent: ComponentType< TP >
+ ): ComponentType< Subtract< TP, TObviatedProps > >;
+}
+
+/**
+ * Given a function mapping a component to an enhanced component and modifier
+ * name, returns the enhanced component augmented with a generated displayName.
+ *
+ * @param mapComponentToEnhancedComponent Function mapping component to enhanced component.
+ * @param modifierName Seed name from which to generated display name.
+ *
+ * @return Component class with generated display name assigned.
+ */
+function createHigherOrderComponent<
+ TObviatedProps extends object,
+ TProps extends TObviatedProps
+>(
+ mapComponentToEnhancedComponent: (
+ OriginalComponent: ComponentType< TProps >
+ ) => ComponentType< Subtract< TProps, TObviatedProps > >,
+ modifierName: string
+): HigherOrderComponent< TObviatedProps > {
+ return ( ( OriginalComponent: ComponentType< TProps > ) => {
+ const EnhancedComponent = mapComponentToEnhancedComponent(
+ OriginalComponent
+ );
+
+ const {
+ displayName = OriginalComponent.name || 'Component',
+ } = OriginalComponent;
+
+ EnhancedComponent.displayName = `${ upperFirst(
+ camelCase( modifierName )
+ ) }(${ displayName })`;
+
+ return EnhancedComponent;
+ } ) as HigherOrderComponent< TObviatedProps >;
+}
+export default createHigherOrderComponent;
diff --git a/packages/compose/tsconfig.json b/packages/compose/tsconfig.json
new file mode 100644
index 00000000000000..63dce7aacabbab
--- /dev/null
+++ b/packages/compose/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "declarationDir": "build-types"
+ },
+ "include": [
+ "src/higher-order/if-condition/**/*",
+ "src/utils/**/*"
+ ]
+}