Typescript 和 CSS 模块类型

Posted

技术标签:

【中文标题】Typescript 和 CSS 模块类型【英文标题】:Typescript and CSS-modules types 【发布时间】:2019-03-05 00:10:12 【问题描述】:

我不想对 CSS 模块使用愚蠢的 mock,而是使用真正的类型,所以我使用 webpack 插件typings-for-css-modules-loader

对于简单的 css

.foo  color: red; 
.bar  color: green; 

可以生成example.css.d.ts声明

export interface ILocals 
  'foo': string;
  'bar': string;

export interface IExampleCss 
  locals: ILocals;
  'foo': string;
  'bar': string;


declare const styles: IExampleCss

export default styles;

所以在我的代码中我可以像这样使用它

import css from './example.css';

const  locals  = css;

<div className=locals.foo>Red</div>
<div className=css.bar>Green</div>

而且 VSCode 知道 locals.foo 和 css.bar 成员

我尝试编写一个函数,它能够在 typescript 中获取任何 css 定义作为输入参数

interface IStringHash 
    [key: string]: string;

interface ICSSLocals 
    locals: IStringHash;
    [key: string]: string | IStringHash;


interface ISomeInterface 
    renderComponent: (css: ICSSLocals): React.ReactNode


const myFunction = (css: IExampleCss) => 
    return (
        <div key="1" className=css.locals.foo>Red</div>
        <div key="2" className=css.bar>Green</div>
    )


const MyRenderer: ISomeInterface = 
    renderComponent: myFunction
                     ^^^^^^^^^^
;

我得到错误:

[ts] Type 'IExampleCss' is not assignable to type 'ICSSLocals'. Type 'IExampleCss' is not assignable to type 'ICSSLocals'. Types of property 'locals' are incompatible. Type 'ILocals' is not assignable to type 'IStringHash'. Index signature is missing in type 'ILocals'.

怎么了?

我在typescript playground写了一个相关的示例

// Declaration with generics
interface IStringHash 
    [key: string]: string;

interface ICSSModule 
    locals: IStringHash;
    [key: string]: string | IStringHash;


interface returnObject 
    a: string,
    b: string


interface ISomeInterface 
    renderComponent: (css: ICSSModule) => returnObject


// usage with certain realisation
export interface ILocals 
  'foo': string;
  'bar': string;

export interface IExampleCss 
  locals: ILocals;
  'foo': string;
  'bar': string;


const myFunction = (css: IExampleCss): returnObject => 
    return 
        a: css.locals.foo,
        b: css.bar
    


const MyRenderer: ISomeInterface = 
    renderComponent: myFunction
      ^^^^^^^
;

这是错误:

[ts] Type '(css: IExampleCss) => returnObject' is not assignable to type '(css: ICSSModule) => returnObject'. Types of parameters 'css' and 'css' are incompatible. Type 'ICSSModule' is not assignable to type 'IExampleCss'. Property ''foo'' is missing in type 'ICSSModule'. (property) ISomeInterface.renderComponent: (css: ICSSModule) => returnObject

【问题讨论】:

您能否提供更多信息,您在使用myFunction 做什么?采用“任何 CSS 声明”似乎并不比仅使用 any 类型好多少。 @Ski 我已经修复了上面的功能 @Ski 我需要类型建议,如果有显示错误 我很困惑:如果myFunction 访问css.locals.foocss.bar,那么它只适用于类名为foobar 的CSS 模块。那么,你为什么要声明 myFunction 采用任何 CSS 模块? @MattMcCutchen 我为服务器和浏览器的使用风格使用了一些加载器——所以它并不那么重要 【参考方案1】:

好的做法是只需要你需要的界面而不是更多。所以看起来bar 不应该在ILocalsfoo 不应该在IExampleCss

export interface ILocals 
  'foo': string;   
//  'bar': string; <--

export interface IExampleCss 
  locals: ILocals;
  // 'foo': string; <--
  'bar': string;


const myFunction = (css: IExampleCss): returnObject => 
    return 
        a: css.locals.foo,
        b: css.bar
    

旁注:对于简单的情况,您不必声明返回类型——它会被推断出来。而如果需要函数返回值的类型,可以使用ReturnType&lt;myFunction&gt;

【讨论】:

css.locals.foo 用于示例显示任何项目都可以直接访问或通过locals 访问 抱歉搞混了,foo 应该留下,bar 应该离开

以上是关于Typescript 和 CSS 模块类型的主要内容,如果未能解决你的问题,请参考以下文章

将 sass/css 模块添加到 typescript react app

Create-react-app + TypeScript + CSS 模块:自动生成类型定义而不从 CRA 中弹出

如何从节点模块中的@types 保存类型

如何手动补充陈年老库(或纯 JS 代码)的 TypeScript 类型?

TypeScript 找不到模块 flatpickr,即使它包含 typescript 类型

为模块定义 TypeScript 类型会给出 TS2665?