styled-components / styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅
https://styled-components.com
MIT License
40.11k stars 2.48k forks source link

Overriding DefaultTheme with custom ThemeType only affects ThemeProvider and not styled components themselves. #4247

Open nat-foo opened 4 months ago

nat-foo commented 4 months ago

Environment

npx envinfo --system --binaries --npmPackages styled-components,babel-plugin-styled-components --markdown

System:

Reproduction

Code Sandbox Reproduction

Steps to reproduce

  1. Setup a standard CRA app and install styled-components (tested with pnpm).
  2. Paste this code into a file:
import styled, { ThemeProvider } from "styled-components"

type ThemeType = {
  test: string
  debug: string
}

declare module "styled-components" {
  export interface DefaultTheme extends ThemeType {}
}

export const CustomText = styled.p`
  // Does not raise type error
  ${(props) => props.theme.anythingiwantgoeshere.text.body.fontFamily.etc}
`

export const App = () => {
  return (
    <ThemeProvider
      theme={{
        text: {
          body: {
            fontFamily: `Raises type error: Type '{ text: { body: { fontFamily: string; }; }; }' is not assignable to type 'ThemeArgument'.
              Type '{ text: { body: { fontFamily: string; }; }; }' is missing the following properties from
              type 'DefaultTheme': test, debug`,
          },
        },
      }}
    />
  )
}
  1. The first usage in CustomText will not result in a type error, but the second usage in ThemeProvider will.

Expected Behavior

Overriding the DefaultTheme interface in the way the docs provide (and in the type declaration for DefaultTheme itself) should result in being able to access the custom theme type when using styled.div${(props) => props.theme.etc}`.

Actual Behavior

It does not. Only the ThemeProvider seems to benefit from the custom typing.

Thanks for your time!

quantizor commented 4 months ago

Confirmed https://codesandbox.io/p/sandbox/wizardly-kapitsa-forked-7lcnhc?file=%2Fsrc%2FApp.tsx%3A11%2C1

Seems like the type is incorrectly widening, maybe because Props defaults to object.

mosherc commented 3 months ago

Yes, we've noticed this too on v6 that any property of theme is allowed.

// computed type of our custom theme:
const theme: {
    [x: string]: any; // any property is allowed incorrectly
    // all the other valid properties that still benefit from autocomplete
}

const Test = styled.div`
  color: ${({ theme }) => theme.gibberish.properties.that.dont.exist}; // incorrect types are OK
`;