Styled-components w/ Typescript: missing type for theme variable

Viewed 2536

The theme variable got the any type just on the top-level. If I'm using theme at a css'' block it got the correct typing DefaultTheme.

Example:

const Header = styled.div<{ invertedColor: boolean }>`
  color: ${({ theme }) => theme.color.blue}; // theme = any

  ${({ invertedColor }) =>
    invertedColor &&
    css`
      color: ${({ theme }) => theme.color.white}; // theme = DefaultTheme (correct)
    `}
`

Also <{ invertedColor: boolean }> is not working since invertedColor is any here.

I've added a styled-components.d.ts with the following content:

import 'styled-components';

type ColorType = 'blue' | 'white';

declare module 'styled-components' {
  export interface DefaultTheme {
    color: Record<ColorType, string>;
  }
}

Using the following versions:

"@types/styled-components": "^5.1.22",
"styled-components": "^5.3.3",

I've tried to debug & check where the type is lost because its correctly passed at the ThemeProvider - also tried every solution from here: https://github.com/styled-components/styled-components/issues/1589

What's the best way to debug that? Any hint?

3 Answers

In typescript, the type definition is very important.

1. theme

import {ThemeProvider} from 'styled-components';

<ThemeProvider theme={theme}>
   //Your children component here
</ThemeProvider>

for types

//./styled-components.d.ts

import themeVariables from '<//theme variables path here>';

type ThemeInterface = typeof themeVariables 

declare module "styled-components" {
  interface DefaultTheme extends ThemeInterface {}
}

//tsconfig.json
{
  "compilerOptions": {
    "includes": ["styled-components.d.ts"]
  }
}

After it, you can use the theme in the styled component

const SomeStyledComponent = styled.div`
   background-color: ${props => props.theme.backgroundColor};
`

2.<{ invertedColor: boolean }> issue

interface SomeComponentProps {
   invertedColor: boolean;
}

const SomeComponent = styled.div<SomeComponentProps>`
  color: ${props => (props.invertedColor ? props.theme.color.white : props.theme.color.dark)}
`

Weird that you're having any for your theme typing.

I'm doing it in a close but different way:

styled-component.d.ts

// import original module declarations
import 'styled-components';
import { ITheme } from './styles/theme';

// and extend them!
declare module 'styled-components' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface DefaultTheme extends ITheme {}
}

I'm extending DefaultTheme with my ITheme object, which is something like that:

import {
  borderRadius,
  boxShadows,
  IBorderRadius,
  IBoxShadows,
  ITransitions,
  IZIndexes,
  transitions,
  zIndexes,
} from './base';
import { colors, IColors } from './colors';
import { ISizes, sizes } from './sizes';

export interface ITheme {
  colors: IColors;
  sizes: ISizes;
  boxShadows: IBoxShadows;
  zIndexes: IZIndexes;
  borderRadius: IBorderRadius;
  transitions: ITransitions;
}

export const Theme: ITheme = {
  colors,
  sizes,
  boxShadows,
  zIndexes,
  borderRadius,
  transitions,
};

And I'm using <ThemeProvider> from import { ThemeProvider } from 'styled-components';

<ThemeProvider theme={Theme}>

I'm using nearly the same versions as you:

"styled-components": "^5.3.3",
"@types/styled-components": "^5.1.19",

And here is my tsconfig.json

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "baseUrl": "src",
    "paths": {
      "~/*": ["./*"]
    }
  },
  "include": [
    "src"
  ]
}

Setting color type is correct.

Looks like typescript is not recognizing your declare module. I used same version of styled-components but instead of styled-components.d.ts, I created styled.d.ts file and I did not have any issue

Related