Create styled.d.ts to make Typescript work with styled-components
Tags: typescript, react, styledcomponents
Published: 2020-09-18 20:02:03


# **TL;DR**
### **Create `theme.ts`** 
I put mine in `/theme/theme.ts`. This is what it looks like:
```javascript
export type ThemeType = typeof light; // This is the type definition for my theme object.

export const light = {
  primary: "#f45511",
  text: "#000",
  background: "#fff",
  ...
}
export const dark: ThemeType = {
  primary: ...
  ...
}

const theme = light; // set the light theme as the default.
export default theme;
```

### **Create styled.d.ts**
I put mine in `/theme/styled.d.ts`. This is what it looks like:

```javascript
import {} from 'styled-components';
import { ThemeType } from './theme'; // Import type from above file
declare module 'styled-components' {
  export interface DefaultTheme extends ThemeType {} // extends the global DefaultTheme with our ThemeType.
}
```

- `import { ThemeType } from './theme';` ->
This line imports my unique theme type definition from the above `theme.ts` file.
- `export interface DefaultTheme extends ThemeType {}` ->
This line extends the global DefaultTheme to now include properties from my ThemeType.

Now `props.theme.primary` will auto-complete and typescript will not have a compile error.

# **The Long Version**
A common pattern in styled-components is to create a top-level theme object (just a plain old object) and have it be passed down to all components using `ThemeProvider`. Here's an example:

```javascript
import { ThemeProvider } from 'styled-components';
import theme from './theme';

const App = () => (
  {/* theme obj being passed down through ThemeProvider */}
  <ThemeProvider theme={theme}>
    <Button>Click Me</Button>
  </ThemeProvider>
)

// button.tsx
const Button = styled.button`
  color: ${props => (
    props.theme.primary
    /* accessing props.theme */
  )};
  background-color: ${props => props.theme.background};
`;

```
As you can see, `ThemeProvider` passes the `theme` object to all child components. In the above case, the `Button` component uses this `theme` object to set its color and background.

Check out the [styled-components docs](https://styled-components.com/docs/advanced#theming) for more details on theme support.

This is all great, but when we use Typescript, it will give us an error since it doesn't know `primary` is a field inside `theme`. Like this:

![Screen Shot 2020-09-18 at 3.32.57 PM](https://dev-to-uploads.s3.amazonaws.com/i/hhvjkoq8axneqv79unh9.png)
 
Typescript is complaining because the default theme object is  just `{}`. The `ThemeProvider` injects an object of type `DefaultTheme` into every prop and the definition for `DefaultTheme` is just `{}`. [Take a look at the type definition](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/styled-components/index.d.ts#L392).

To solve this we need to use declaration merging and extend `DefaultTheme`. I've found the best way to do this is:

### **Create `theme.ts`**
Create `theme.ts`. I usually create this in `/theme/theme.ts`. This is an example of what it could look like:
```javascript
export type ThemeType = typeof light; // This is the type definition for my theme object.

export const light = {
  primary: "#f45511",
  text: "#000",
  background: "#fff",
  ...
}
export const dark: ThemeType = {
  primary: ...
  ...
}

const theme = light; // set the light theme as the default.
export default theme;
```

This creates the theme, but also exports a `ThemeType` to be used by `styled.d.ts` below.

### **Create `styled.d.ts`**
Create a `styled.d.ts` file in your project anywhere (most likely your bundler will pick it up. If not, that's something you'll have to look into).

Add this code to extend the `DefaultTheme` and merge it with `ThemeType` from your `theme.ts` file.

```javascript
import {} from 'styled-components';
import { ThemeType } from './theme'; // Import type from above file
declare module 'styled-components' {
  export interface DefaultTheme extends ThemeType {} // extends the global DefaultTheme with our ThemeType.
}
```

That's it! You're typescript compiler and VSCode should stop complaining about `props.theme.primary`.

If you enjoyed this post... I have nothing to ask of you. Cheers.