user3283390
user3283390

Reputation: 79

React Typescript: property 'body' does not exist type 'DefaultTheme'

I am new to React and Typescript, I am trying to add dark-mode to my project, I created globalStyle component, Themes component and using Themeprovider.

I am facing an issue on my globalStyle component when it says: property 'body' does not exist type 'DefaultTheme'

My globalStyles.tsx code is as follow:

import { createGlobalStyle} from "styled-components"
export const GlobalStyles = createGlobalStyle`
  body {
    background: ${({ theme }) => theme.body};
    color: ${({ theme }) => theme.text};
    font-family: Tahoma, Helvetica, Arial, Roboto, sans-serif;
    transition: all 0.50s linear;
  }`

my Themes.tsx:

export const lightTheme = {
    body: '#FFF',
    text: '#363537',
    background: '#363537',
}
export const darkTheme = {
    body: '#363537',
    text: '#FAFAFA',
    background: '#999',
}

and my Themeprovider code on App.tsx:

<ThemeProvider theme={this.state.theme === 'light' ? lightTheme : darkTheme}>
        <>
        <GlobalStyles/>
            <ul className='tickets'>
                {filteredTickets.map((ticket) => (
                <li key={ticket.id} className={ticket.toggle ? 'expand' : 'ticket'}>
                    <h5 className='title'>{ticket.title}</h5>
                    <button onClick={() => this.onHide(ticket.id)}>Hide</button>
                    <p className={ticket.toggle ? 'show-more' : 'content'}>{ticket.content}</p>
                    <button onClick={()=> this.onToggle(ticket.id)}>{ticket.toggle ? 'Show less' : 'Show more'}</button>
                    <footer>
                        <div className='meta-data'>By {ticket.userEmail} | { new Date(ticket.creationTime).toLocaleString()}</div>
                    </footer>
                </li>))}
            </ul>
        </>
        </ThemeProvider>

What am I doing wrong and why theme.body and theme.text is not recognized on globalStyles.tsx?

Thanks !

Upvotes: 8

Views: 14386

Answers (3)

Webfer
Webfer

Reputation: 151

Based on the styled-components docs (https://styled-components.com/docs/api#typescript) I created an interface for the body type:

export interface DefaultTheme {
  body: string;
}

export const GlobalStyle = createGlobalStyle<{ theme: DefaultTheme }>`

body{
  background-color: ${({ theme }) => theme.body};
  color: var(--font-color);
}

`;

This works pretty well for me.

Upvotes: 2

wynx
wynx

Reputation: 323

So the answer above fails, as useTheme does not know what type you passed to createGlobalStyles.

But this is a typescript workaround that doesn't require you to use ts-ginore:

  1. As jnpdx suggested, you do need to type the createGlobalTheme object:

createGlobalStyle<{theme: ThemeType}>

  1. The only working solution I have figured out so far is to post-type your useTheme variable like so:

const theme = useTheme() as ThemeType;

Upvotes: 1

jnpdx
jnpdx

Reputation: 52535

I'm basing this answer on the following link: https://spectrum.chat/styled-components/general/i-cant-use-my-theme-in-createglobalstyle-function-styled-components-v4-react-v16-6-3~0978b404-ab71-45c9-8f75-0862abde4eb5

createGlobalStyle can accept a shape for the theme:

createGlobalStyle<{theme: ThemeType}>

From the styled-components docs, there's this (https://styled-components.com/docs/api#typescript):

declare module 'styled-components' {
  export interface DefaultTheme {
    borderRadius: string;

    colors: {
      main: string;
      secondary: string;
    };
  }
}

So, I suggest you set up an interface for your theme, as above, and then pass it into createGlobalStyle in place of ThemeType

Upvotes: 19

Related Questions