ค้นหาเว็บไซต์

reactjs - Styled-components กับ Typescript: ขาดชนิดสำหรับตัวแปรธีม


ตัวแปร theme ได้ชนิด any เพียงในระดับบนสุดเท่านั้น ถ้าฉันใช้ theme ในบล็อก css'' มันจะได้การพิมพ์ที่ถูกต้อง DefaultTheme

ตัวอย่าง :

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

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

นอกจากนี้ <{ invertedColor: boolean }> ก็ไม่ทำงานเนื่องจาก invertedColor เป็น any ที่นี่

ฉันได้เพิ่ม styled-components.d.ts พร้อมกับเนื้อหาดังต่อไปนี้:

import 'styled-components';

type ColorType = 'blue' | 'white';

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

โดยใช้เวอร์ชันดังต่อไปนี้:

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

ฉันได้พยายามดีบั๊กและตรวจสอบว่าประเภทหายไปที่ไหน เพราะมันถูกส่งไปอย่างถูกต้องที่ ThemeProvider - และยังได้ลองใช้ทุกวิธีแก้ปัญหาจากที่นี่ด้วย: https://github.com/styled-components/styled-components/issues/1589

วิธีที่ดีที่สุดในการดีบั๊กเรื่องนั้นคืออะไร มีคำใบ้ไหม?

คำตอบ #1

แปลกที่คุณกำลังมี any สำหรับการพิมพ์ธีมของคุณ

ฉันกำลังทำมันในวิธีที่ใกล้เคียงแต่ต่างออกไป:

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 {}
}

ฉันกำลังขยาย DefaultTheme ด้วยวัตถุ ITheme ของฉัน ซึ่งเป็นบางสิ่งที่มีลักษณะประมาณนี้:

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,
};

และฉันกำลังใช้ <ThemeProvider> จาก import { ThemeProvider } from 'styled-components';

<ThemeProvider theme={Theme}>

ฉันใช้เวอร์ชันที่เกือบจะเหมือนกับของคุณ:

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

และนี่คือ 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"
  ]
}

คำตอบ #2

ในไทป์สคริปต์ การกำหนดประเภทมีความสำคัญมาก

1. ธีม

import {ThemeProvider} from 'styled-components';

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

สำหรับประเภท

//./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"]
  }
}

หลังจากนั้น คุณสามารถใช้ธีมในคอมโพเนนต์ที่มีการจัดสไตล์ได้

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

2.<{ invertedColor: boolean }> ปัญหา

interface SomeComponentProps {
   invertedColor: boolean;
}

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

บทความที่เกี่ยวข้อง