diff --git a/__tests__/typingTests/tsconfig.json b/__tests__/typingTests/tsconfig.json
new file mode 100644
index 000000000..a3429c31e
--- /dev/null
+++ b/__tests__/typingTests/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "strict": true
+ }
+}
diff --git a/__tests__/typingTests/typingTests.tsx b/__tests__/typingTests/typingTests.tsx
new file mode 100644
index 000000000..723fb8271
--- /dev/null
+++ b/__tests__/typingTests/typingTests.tsx
@@ -0,0 +1,47 @@
+// this file doesn't actually run with the test runner. it is just used to
+// verify the typings work as expected
+import * as React from 'react';
+import { withController, WithControllerInjectedProps } from '../../src';
+
+describe('typescript tests: withController', () => {
+ it("has an error because the `TestProps` don't include `parallaxController`", () => {
+ interface TestProps {
+ foo: string;
+ }
+
+ function TestComponent({ }: TestProps) {
+ return null;
+ }
+
+ // expect TS error here
+ withController(TestComponent);
+ });
+
+ it("doesn't error if `TestProps` include `parallaxController`", () => {
+ interface TestProps extends WithControllerInjectedProps {
+ foo: string;
+ }
+
+ function TestComponent({ }: TestProps) {
+ return null;
+ }
+
+ // should _not_ have an error
+ withController(TestComponent);
+ });
+
+ it('removes the `parallaxController` prop from the wrapped component', () => {
+ interface TestProps extends WithControllerInjectedProps {
+ foo: string;
+ }
+
+ function TestComponent({ foo }: TestProps) {
+ return null;
+ }
+
+ const Enhanced = withController(TestComponent);
+
+ // should _not_ have an error because the prop `parallaxController` was removed
+ const x = ;
+ });
+});
diff --git a/package.json b/package.json
index 23988b2bb..84e90f2c6 100644
--- a/package.json
+++ b/package.json
@@ -73,6 +73,8 @@
"@storybook/addon-links": "^5.0.6",
"@storybook/addons": "^5.0.6",
"@storybook/react": "^5.0.6",
+ "@types/jest": "^24.0.11",
+ "@types/react": "^16.8.10",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.4.2",
diff --git a/src/index.d.ts b/src/index.d.ts
new file mode 100644
index 000000000..b94e845e5
--- /dev/null
+++ b/src/index.d.ts
@@ -0,0 +1,118 @@
+import * as React from 'react';
+
+// ========================
+// === ParallaxProvider ===
+// ========================
+export interface ParallaxProviderProps {
+ /**
+ * Optionally pass the scroll axis for setting horizontal/vertical scrolling. One of vertical or
+ * horizontal
+ */
+ scrollAxis?: 'vertical' | 'horizontal';
+ /**
+ * Optionally set the container that has overflow and will contain parallax elements. Defaults
+ * to the HTML body
+ */
+ scrollContainer?: any;
+}
+export const ParallaxProvider: React.ComponentType;
+
+// ================
+// === Parallax ===
+// ================
+export interface ParallaxProps {
+ /**
+ * Offsets on x-axis in % or px. If no unit is passed percent is assumed. Percent is based on
+ * the elements width.
+ */
+ x?: Array;
+ /**
+ * Offsets on y-axis in % or px. If no unit is passed percent is assumed. Percent is based on
+ * the elements width.
+ */
+ y?: Array;
+ /**
+ * Optionally pass additional class names to be added to the outermost parallax element.
+ */
+ className?: string;
+ /**
+ * Disables parallax effects on individual elements when true.
+ */
+ disabled?: boolean;
+ /**
+ * Optionally pass a style object to be added to the innermost parallax element.
+ */
+ styleInner?: any;
+ /**
+ * Optionally pass a style object to be added to the outermost parallax element.
+ */
+ styleOuter?: any;
+ /**
+ * Optionally pass an element tag name to be applied to the innermost parallax element.
+ */
+ tagInner?: any;
+ /**
+ * Optionally pass an element tag name to be applied to the outermost parallax element.
+ */
+ tagOuter?: any;
+}
+export const Parallax: React.ComponentType;
+
+// =======================
+// === Parallax Banner ===
+// =======================
+export interface BannerLayer {
+ /**
+ * A value from `-1` to `1` that represents the vertical offset to be applied to the current
+ * layer, `0.1` would equal a `10%` offset on the top and bottom.
+ */
+ amount: number;
+ /**
+ * Custom layer children provided as a React element, for example ``
+ */
+ children: any;
+ /**
+ * Indicate if the layer should be expanded with negative top/bottom margins so the edges will
+ * never be visible.
+ */
+ expanded?: boolean;
+ /**
+ * Image source that will be applied as a CSS background image on the layer.
+ */
+ image?: string;
+}
+
+export interface ParallaxBannerProps {
+ /**
+ * Optionally pass additional class names to be added to the outermost parallax banner element.
+ */
+ className?: string;
+ /**
+ * Determines if the internal parallax layers will have offsets applied.
+ */
+ disabled?: boolean;
+ /**
+ * A required Array of Objects with layer properties: `[{ amount: 0.1, image: 'foo.jpg' }]`.
+ */
+ layers: BannerLayer[];
+ /**
+ * Optionally pass a style object to be added to the outermost parallax banner element.
+ */
+ style?: any;
+}
+export const ParallaxBanner: React.ComponentType;
+
+export interface ParallaxController {
+ update(): void;
+ destroy(): void;
+}
+export interface WithControllerInjectedProps {
+ parallaxController: ParallaxController;
+}
+
+// helper to remove props from a type
+type RemoveProps = Pick>;
+
+export function withController