You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

发布的styled-components UI库无法在消费端获取扩展主题类型

如何在styled-components UI库中向消费端传递扩展的DefaultTheme类型

我用styled-components开发UI库时,基于内部依赖包的类型扩展了DefaultTheme,在UI库内部开发组件一切正常,但消费端使用主题时,扩展的类型没正确传递——如果不在消费端手动添加styled.d.ts,主题类型会被识别为any而非自定义的DefaultTheme。想找一种不用让用户额外加文件就能把扩展类型暴露给消费端的方法,有没有可行的方案?


设计系统项目代码

theme.ts

import tokens from 'my-external-package/variables.json';
import type { ThemeProps } from 'styled-components';
import type { MyThemeType } from 'my-external-package/theme';

const { light, dark } = tokens.color.theme;

export const lightTheme = {
  color: light,
};

export const darkTheme = {
  color: dark,
};

export const defaultTheme = lightTheme;

styled.d.ts

import {} from 'styled-components';
import type { MyThemeType } from 'my-external-package/theme';

// 扩展主题类型
declare module 'styled-components' {
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
  export interface DefaultTheme extends MyThemeType {}
}

CustomThemeProvider.tsx

import React, { createContext, useState, ReactNode, useContext } from 'react';
import { ThemeProvider } from 'styled-components';
import { lightTheme, darkTheme } from './theme';

const themes = {
  light: lightTheme,
  dark: darkTheme,
};

type CustomThemeProviderProps = {
  children: ReactNode;
  defaultTheme?: keyof typeof themes;
};

const themeContext = createContext({ toggleTheme: () => {} });

const { Provider } = themeContext;

export const CustomThemeProvider = ({
  children,
  defaultTheme = 'light',
}: CustomThemeProviderProps) => {
  const [currentTheme, setCurrentTheme] = useState(defaultTheme);
  
  return (
    <Provider
      value={{
        toggleTheme: () =>
          setCurrentTheme((current) => current === 'light' ? 'dark' : 'light'),
      }}
    >
      <ThemeProvider theme={themes[currentTheme]}>{children}</ThemeProvider>
    </Provider>
  );
};

// 导出切换主题钩子供消费端使用
export const useToggleTheme = () => {
  const { toggleTheme } = useContext(themeContext);
  return toggleTheme;
};

Next.js消费端项目代码

_app.tsx

import type { AppProps } from 'next/app';
import { CustomThemeProvider } from 'my-library-package/theming';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <CustomThemeProvider defaultTheme='light'>
      <Component {...pageProps} />
    </CustomThemeProvider>
  );
}
export default MyApp;

consumer_page.tsx

import type { NextPage } from 'next';
import styled from 'styled-components';
import { useToggleTheme, Switch } from 'my-library-package';

const CustomComponent = styled.p`
  color: ${({ theme }) => theme.color.feedback.success.foreground};
`;

const MyPage: NextPage = () => {
 const toggleTheme = useToggleTheme();

 return (
  <>
   <Switch onChange={toggleTheme}/>
   <CustomComponent>This component have access to theme</CustomComponent>
  </>
 )
}

export default MyPage;

现有备选方案(均较繁琐)

  • 重新导出带有正确DefaultTheme的styled-components工具,要求消费者不要自行安装styled-components
  • 要求消费端创建styled.d.ts文件以识别主题类型

可行解决方案

1. 配置typesVersions自动加载类型扩展

在UI库的package.json中添加typesVersions字段,指定TypeScript自动加载你的主题类型扩展文件:

{
  "typesVersions": {
    "*": {
      "*": ["./types/*"]
    }
  }
}

将styled.d.ts移动到UI库的types目录下(或直接在字段中指定对应路径),消费端安装库后,TypeScript会自动识别该扩展,无需手动配置。

2. 将类型扩展纳入库的入口类型

修改UI库的package.json,将types指向一个入口声明文件:

{
  "types": "./index.d.ts"
}

在index.d.ts中导入主题类型扩展及其他导出内容:

export * from './styled.d.ts';
export * from './CustomThemeProvider';
// 其他组件、类型的导出

这样TypeScript解析库类型时,会自动加载styled.d.ts中的扩展,覆盖styled-components的DefaultTheme类型。

3. 确保类型文件被正确打包

在UI库的tsconfig.json中,确保styled.d.ts被包含在编译范围内:

{
  "include": ["src/**/*", "src/styled.d.ts"]
}

同时在package.json的files字段中添加类型文件,确保发布时被打包:

{
  "files": ["dist", "src/styled.d.ts"]
}

消费端安装后即可自动读取到类型扩展。

另外,建议将styled-components设为UI库的peerDependency并指定版本范围,避免消费端安装多个版本导致类型冲突。


内容的提问来源于stack exchange,提问作者Patrycja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 23:30:53