Twiggeh
Twiggeh

Reputation: 1160

EmotionJS with typescript doesn't pass theme type to props in styled components

emotion.d.ts

import '@emotion/react';

declare module '@emotion/react' {
    export interface Theme {
        colors: {
            primaryColor: string;
            accentColor: string;
        };
    }
}

App.tsx

import { Theme, ThemeProvider } from '@emotion/react';

const theme: Theme = {
    colors: {
        accentColor: 'hotpink',
        primaryColor: 'aqua',
    },
};
...

return (
<ThemeProvider theme={theme}>

...

Button.tsx

const StyledButton = styled.a`
    ${({ theme }) =>
        `background-color: ${theme.colors.accentColor};`
    }`;

tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "allowSyntheticDefaultImports": true,
        "moduleResolution": "node",
        "sourceMap": true,
        "typeRoots": ["src/@types"],
        "jsx": "react",
        "strict": true,
        "strictNullChecks": true,
        "baseUrl": "./",
        "paths": {
            "*": ["src/@types/*"]
        }
    },
    "compileOnSave": false,
    "include": ["src/**/*"]
}
src
|=>@types
  |> emotion.d.ts
|=> components
|> App.tsx

Property 'colors' does not exist on type 'object'.

Am I doing something wrong or did I misread the documentation ?

Right now I am manually adding the theme by passing it to the styled constructor :


type StyledProps = Pick<ButtonProps, 'bgColor' | 'fColor'> & { theme: Theme };

const StyledButton = styled.a<StyledProps>`
...

Removing the passed type doesnt't help either.

It seems like the d.ts file is picked up correctly, because I can import the correct theme type from "@emtion/react" with import { Theme } from "@emotion/react" and use that to type the props.theme in the styled components

Repro

Upvotes: 7

Views: 6824

Answers (1)

tmhao2005
tmhao2005

Reputation: 17474

Based on your provided code, I would think the error is supposed to be:

Property 'accentColor' does not exist on type 'Theme'. // instead of object

Anyway your Theme object now nested by colors at the top level so you might change to:

const StyledButton = styled.a`
  ${({ theme }) =>
      `background-color: ${theme.colors.accentColor};` // `accentColor` is nested in `colors`
  }`;

Keep in mind, you also need to include your defined type in build process in tsconfig.json file via include option.

Update regarding to unable override Theme via the custom type file

As I've seen the styled type only consume Theme object from @emotion/react at least from version ^11.0.0.

In short, you have to update @emotion/styled to from this version ^11.0.0 to make it work as expected:

{
  "dependencies": {
    // ...
    "@emotion/styled": "^11.0.0",
  }
}

Upvotes: 4

Related Questions