)
+) {
+  return function(WrappedComponent: React.ComponentClass
): React.FC
 {
+    const useStyles = createUseStyles(styles)
+
+    const StyledComponent: React.FC = (props: P) => {
+      const {classes, ...passThroughProps} = props
+      const theme = useTheme()
+      const reactJssClasses = useStyles({...(passThroughProps as P), theme})
+
+      return 
+    }
+
+    StyledComponent.displayName = `withStyles(${WrappedComponent.name})`
+
+    return StyledComponent
+  }
+}
+
+export default withStyles
+```
+
+This typed HOC enforces consistency with your `RuleNames` and `Theme`. It also enforces consistency between the `Props` you give to `Styles` and the ones you give to your component.
+
+You'll notice that here, we've typed the HOC to accept only class components as arguments. This is because you should be using the provided hooks for your functional components; not only do hooks provide a simpler interface, but they also help clarify which props actually belong to your component.
+
+## Migrating from Decorators
+
+Because this custom HOC makes use of hooks (which are [unusable in class components](https://reactjs.org/docs/hooks-faq.html#:~:text=You%20can't%20use%20Hooks,implementation%20detail%20of%20that%20component.)), you won't be able to use this HOC as a decorator. If you are using decorators in your project, you'll likely have to migrate your code from this:
+
+```javascript
+import React from 'react'
+import decorator1 from 'some-hoc-library'
+import decorator2 from 'another-hoc-library'
+// ...
+import withStyles from 'path/to/custom-hoc'
+
+const styles = {
+  /* ... */
+}
+
+@decorator1
+@decorator2
+// ...
+@withStyles(styles)
+class MyComponent extends React.Component {
+  // ...
+}
+
+export default MyComponent
+```
+
+to this:
+
+```javascript
+import React from 'react'
+import decorator1 from 'some-hoc-library'
+import decorator2 from 'another-hoc-library'
+// ...
+import withStyles from 'path/to/custom-hoc'
+
+const styles = {
+  /* ... */
+}
+
+@decorator1
+@decorator2
+// ...
+class MyComponent extends React.Component {
+  // ...
+}
+
+export default withStyles(styles)(MyComponent)
+```
+
+If you find yourself using many decorators for your class components, consider migrating away from chained decorators to [composed function calls](https://reactjs.org/docs/higher-order-components.html#convention-maximizing-composability). This is a safer play in the long run since decorators still have not stabilized in the JS standard.
+
+If you don't use decorators or aren't familiar with them, then this won't be a concern for you.
diff --git a/docs/react-jss.md b/docs/react-jss.md
index 9d01c3841..00c81cd5a 100644
--- a/docs/react-jss.md
+++ b/docs/react-jss.md
@@ -4,7 +4,7 @@ React-JSS integrates [JSS](https://github.com/cssinjs/jss) with React using the
 
 Try it out in the [playground](https://codesandbox.io/s/j3l06yyqpw).
 
-**The HOC based API is deprecated as of v10 and may be removed in a future version. You can still perform a lazy migration as described [here](https://reacttraining.com/blog/using-hooks-in-classes/). HOC specific docs are available [here](./react-jss-hoc.md).**
+**The HOC-based API is deprecated as of v10 and may be removed in a future version. You can still perform a lazy migration as described [here](react-jss-hoc-migration.md). Documentation for the deprecated HOC-based API is available [here](react-jss-hoc.md).**
 
 ### Benefits compared to using the core JSS package directly:
 
diff --git a/package.json b/package.json
index 759666218..f6876e2a3 100644
--- a/package.json
+++ b/package.json
@@ -99,7 +99,7 @@
     "rollup-plugin-terser": "^7.0.2",
     "shelljs": "^0.8.2",
     "sinon": "4.5.0",
-    "typescript": "^3.7.0",
+    "typescript": "^4.2.3",
     "webpack": "^4.28.3",
     "zen-observable": "^0.6.0"
   }
diff --git a/packages/react-jss/tests/types/withStyles.tsx b/packages/react-jss/tests/types/withStyles.tsx
index b7dfa9aa1..dfb8e4419 100644
--- a/packages/react-jss/tests/types/withStyles.tsx
+++ b/packages/react-jss/tests/types/withStyles.tsx
@@ -15,8 +15,10 @@ interface MyTheme {
   color: 'red'
 }
 
-function SimpleComponent(props: MyProps) {
-  return {props.property}
+class SimpleComponent extends React.Component {
+  render() {
+    return {this.props.property}
+  }
 }
 
 // Intended to test the output of withStyles to make sure the props are still valid
@@ -137,7 +139,7 @@ ComponentTest = () => 
 /* -------------------- Failing Cases -------------------- */
 
 // A function argument cannot provide another defined theme type conflicting with `undefined`
-function failingFunctionRedefineTheme(theme: MyTheme): Styles {
+function failingFunctionNullTheme(theme: MyTheme): Styles {
   return {
     someClassName: '',
     anotherClassName: {
@@ -146,7 +148,7 @@ function failingFunctionRedefineTheme(theme: MyTheme): Styles {
+function passingFunctionAnyTheme(theme: MyTheme): Styles {
   return {
     someClassName: '',
     anotherClassName: {
@@ -155,7 +157,7 @@ function passingFunctionUnknownTheme(theme: MyTheme): Styles {
+function passingFunctionUnknownTheme(theme: MyTheme): Styles {
   return {
     someClassName: '',
     anotherClassName: {
@@ -165,6 +167,6 @@ function passingFunctionNullTheme(theme: MyTheme): Styles
 }
 
 // @ts-expect-error
-withStyles(failingFunctionRedefineTheme)(SimpleComponent)
+withStyles(failingFunctionNullTheme)(SimpleComponent)
+withStyles(passingFunctionAnyTheme)(SimpleComponent)
 withStyles(passingFunctionUnknownTheme)(SimpleComponent)
-withStyles(passingFunctionNullTheme)(SimpleComponent)
diff --git a/packages/react-jss/tests/types/withStylesMigration.tsx b/packages/react-jss/tests/types/withStylesMigration.tsx
new file mode 100644
index 000000000..e0178c36e
--- /dev/null
+++ b/packages/react-jss/tests/types/withStylesMigration.tsx
@@ -0,0 +1,223 @@
+import React from 'react'
+import {createUseStyles, useTheme, Styles} from 'react-jss'
+
+/* -------------------- Defined HOC for Docs -------------------- */
+type ReactJSSProps = {classes?: ReturnType>}
+
+/**
+ * Creates a Higher Order Component that injects the CSS specified in `styles`.
+ * @param styles
+ */
+function withStyles(
+  styles: Styles | ((theme: T) => Styles)
+) {
+  return function(WrappedComponent: React.ComponentClass
): React.FC
 {
+    const useStyles = createUseStyles(styles)
+
+    const StyledComponent: React.FC = (props: P) => {
+      const {classes, ...passThroughProps} = props
+      const theme = useTheme()
+      const reactJssClasses = useStyles({...(passThroughProps as P), theme})
+
+      return 
+    }
+
+    StyledComponent.displayName = `withStyles(${WrappedComponent.name})`
+
+    return StyledComponent
+  }
+}
+
+export default withStyles
+
+/* ------------------------------ Tests for HOC (should mimic withStyles.tsx tests) ------------------------------ */
+
+// Note: Styles type is thoroughly tested in `jss/tests/types/Styles` and `react-jss/tests/types/createUseStyles`.
+// This is simply a test to make sure `withStyles` accepts and rejects the correct arguments.
+
+// Note: Testing default theme vs. custom theme is unnecessary here since the user will
+// always have to specify the theme anyway.
+
+interface MyProps {
+  classes?: Record
+  property: string
+}
+
+interface MyTheme {
+  color: 'red'
+}
+
+class SimpleComponent extends React.Component {
+  render() {
+    return {this.props.property}
+  }
+}
+
+// Intended to test the output of withStyles to make sure the props are still valid
+let ResultingComponent: React.ComponentType
+let ComponentTest: React.FC
+
+/* -------------------- Function Argument Passing Cases -------------------- */
+// Plain Object (no type supplied)
+function functionPlainObject(theme: MyTheme) {
+  return {
+    someClassName: '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+ResultingComponent = withStyles(functionPlainObject)(SimpleComponent)
+ComponentTest = () => 
+
+// Plain Styles
+function functionPlainStyles(theme: MyTheme): Styles {
+  return {
+    someClassName: '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+ResultingComponent = withStyles(functionPlainStyles)(SimpleComponent)
+ComponentTest = () => 
+
+// With Props
+function functionProps(theme: MyTheme): Styles {
+  return {
+    someClassName: ({property}) => '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+ResultingComponent = withStyles(functionProps)(SimpleComponent)
+ComponentTest = () => 
+
+// With Props and ClassName rules
+function functionPropsAndName(theme: MyTheme): Styles {
+  return {
+    [1]: ({property}) => '',
+    [2]: {
+      fontWeight: 'bold'
+    }
+  }
+}
+ResultingComponent = withStyles(functionPropsAndName)(SimpleComponent)
+ComponentTest = () => 
+
+/* -------------------- Regular Object Passing Cases -------------------- */
+
+// Plain Object (no type supplied)
+const plainObject = {
+  someClassName: '',
+  anotherClassName: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(plainObject)(SimpleComponent)
+ComponentTest = () => 
+
+// Plain Styles
+const stylesPlain: Styles = {
+  someClassName: '',
+  anotherClassName: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(stylesPlain)(SimpleComponent)
+ComponentTest = () => 
+
+// With Props
+const stylesProps: Styles = {
+  someClassName: ({property}) => '',
+  anotherClassName: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(stylesProps)(SimpleComponent)
+ComponentTest = () => 
+
+// With Theme
+const stylesTheme: Styles = {
+  someClassName: ({theme}) => '',
+  anotherClassName: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(stylesTheme)(SimpleComponent)
+ComponentTest = () => 
+
+// With Props and Theme
+const stylesPropsAndTheme: Styles = {
+  someClassName: ({property, theme}) => '',
+  anotherClassName: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(stylesPropsAndTheme)(SimpleComponent)
+ComponentTest = () => 
+
+// With Props and Theme and ClassName rules
+const stylesPropsAndThemeAndName: Styles = {
+  [1]: ({property, theme}) => '',
+  [2]: {
+    fontWeight: 'bold'
+  }
+}
+ResultingComponent = withStyles(stylesPropsAndThemeAndName)(SimpleComponent)
+ComponentTest = () => 
+
+/* -------------------- Failing Cases -------------------- */
+
+// A function argument cannot provide another defined theme type conflicting with `undefined`
+function passingFunctionAnyTheme(theme: MyTheme): Styles {
+  return {
+    someClassName: '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+
+function passingFunctionUnknownTheme(theme: MyTheme): Styles {
+  return {
+    someClassName: '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+
+function failingFunctionNullTheme(theme: MyTheme): Styles {
+  return {
+    someClassName: '',
+    anotherClassName: {
+      fontWeight: 'bold'
+    }
+  }
+}
+
+// @ts-expect-error
+withStyles(failingFunctionNullTheme)(SimpleComponent)
+withStyles(passingFunctionAnyTheme)(SimpleComponent)
+withStyles(passingFunctionUnknownTheme)(SimpleComponent)
+
+// A functional component cannot be passed to the HOC
+const SimpleFunctionComponent: React.FC = () => This should fail
+
+// @ts-expect-error
+withStyles({})(SimpleFunctionComponent)
+
+// Conflicting props are not allowed
+interface ConflictingProps {
+  classes?: Record
+  invalidProp: number
+}
+
+const conflictingStyles: Styles = {
+  someClassName: props => ({fontSize: props.invalidProp})
+}
+
+// @ts-expect-error
+withStyles(conflictingStyles)(SimpleComponent)
diff --git a/yarn.lock b/yarn.lock
index 70fa8bbee..6d686d744 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10030,10 +10030,10 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
-typescript@^3.7.0:
-  version "3.9.3"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.3.tgz#d3ac8883a97c26139e42df5e93eeece33d610b8a"
-  integrity sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==
+typescript@^4.2.3:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3"
+  integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==
 
 uglify-js@^3.1.4:
   version "3.8.0"