在 Typescript、Webpack、React 项目中使用 css-in-js 时没有重载匹配此调用错误
Posted
技术标签:
【中文标题】在 Typescript、Webpack、React 项目中使用 css-in-js 时没有重载匹配此调用错误【英文标题】:No overload matches this call Error while using css-in-js in Typescript, Webpack, React Project 【发布时间】:2021-05-30 15:34:49 【问题描述】:我有 Webpack、Typescript 和 React Hooks 项目,我在其中使用 CSS-in-js 将样式传递给 div。当我将鼠标悬停在 Menu
组件中的 style
道具上时,出现以下错误。我不确定应该在哪里绑定 CSSProperties。
(JSX attribute) React.htmlAttributes<HTMLDivElement>.style?: React.CSSProperties
Type ' display: string; margin: number; padding: number; alignItems: string; flexDirection: string; justifyContent: string; width: string; height: string; background: string; ' is not assignable to type 'CSSProperties'.
Types of property 'flexDirection' are incompatible.
Type 'string' is not assignable to type 'FlexDirection'.ts(2322)
index.d.ts(1768, 9): The expected type comes from property 'style' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'
菜单组件:
import React from 'react';
const Menu = () => (
<div maxWidth="lg" style=styles.menuContainer>
MENU COMPONENT
</div>
)
export default Menu;
const styles =
menuContainer:
display: 'flex',
margin: 0,
padding: 0,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-around',
width: '100%',
height: '5vh',
background: 'rgba(212, 15, 24,0.8)',
;
tsconfig.json:
"compilerOptions":
"outDir": "./public",
"noImplicitAny": true,
"module": "AMD",
"target": "es6",
"jsx": "react",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"esModuleInterop": true
,
"include": [ "src", "image.d.ts" ],
"exclude": [ "node_modules", "**/*.spec.ts" ]
【问题讨论】:
如果我将 css-in-js 替换为内联样式 style=border: '1px solid red' ,TS 编译器不会抛出任何错误。 以下作品:- 导出常量样式:React.CSSProperties = display: "flex" ;我正在寻找的是在样式属性中创建不同样式的对象,例如outerContainer,innerContainer,它们不起作用。 【参考方案1】:以下两者有区别:
<Component style= flexDirection: 'row' />
// compared to
const style = flexDirection: 'row' ;
<Component style= flexDirection: 'row' />;
根据style
属性后面的类型,即React.CSSProperties
,它预计flexDirection
的类型为FlexDirection
,这是'row' | 'column' | ...
的联合类型。
在第一种情况下,TypeScript 足够聪明,可以意识到您正在尝试构造一个 React.CSSProperties
,因此它会说“我们期望其中一个字符串值,而 'row'
就是其中之一,很好”。
在第二种情况下,当您预定义对象时,TypeScript 执行type widening 并且基本上认为flexDirection
只是一个字符串。 通常是这种情况,这就是为什么它是默认解释。 但是,当您将此值传递给 style
时,它现在会将您的对象的 flexDirection
视为 string
而不是 @ 987654334@常量。
多年来我提出的对开发人员最友好的解决方案(我和我的朋友有时都偶然发现了这个问题,尽管并不总是与 React 有关)是使用一种通用帮助函数:
// Using this as example, but you can directly use React.CSSProperties
// (or really any other type that benefits from this "pattern" below)
interface CSSProperties
flexDirection?: 'row' | 'column';
// This simply returns the object itself, but we benefit from the special typing.
// As for the cost of a single simple function call? Negligible and worth it.
function checkStylesheets<T extends [key in keyof T]: CSSProperties >(obj: T): T
return obj;
// To showcase the original problem: TypeScript sees 'row' as just a string
const widenedStyle = flexDirection: 'row' ;
// typeof widenedStyle = flexDirection: string
const styles = checkStylesheets(
menuContainer:
flexDirection: 'row',
,
unknownProperty:
// Type ' nonExistingField: number; ' is not assignable to type 'CSSProperties'.
// Object literal may only specify known properties, and 'nonExistingField' does not exist in type 'CSSProperties'.ts(2322)
nonExistingField: 123,
,
invalidFlexDirection:
// Type '"invalid"' is not assignable to type '"row" | "column" | undefined'.ts(2322)
flexDirection: 'invalid',
,
notEvenAString:
// Type 'number' is not assignable to type '"row" | "column" | undefined'.ts(2322)
flexDirection: 5,
);
// typeof styles =
// menuContainer: CSSProperties;
// unknownProperty: CSSProperties;
// invalidFlexDirection: CSSProperties;
// notEvenAString: CSSProperties;
//
const someStyle: CSSProperties = styles.menuContainer;
// Property 'nonExistingName' does not exist on type ' menuContainer: CSSProperties; unknownProperty: CSSProperties; invalidFlexDirection: CSSProperties; notEvenAString: CSSProperties; '.ts(2339)
const anotherStyle: CSSProperties = styles.nonExistingName;
使用自定义 CSSProperties
接口简化了示例
上述解决方案/示例列出了 cmets 中的一些结果样式,以及它产生的所有 TypeScript 错误。
问:为什么需要辅助函数?为什么不简单地将styles
的类型设置或强制转换为Record<string, CSSProperties>
或类似的类型?
A:通过使用这个技巧,checkStylesheets
将验证传递的对象是否符合作为只有 CSSProperties
字段的对象的要求。但由于与keyof T
的通用性,它将具有相同键的对象,但作为值CSSProperties
。
这样做的主要好处是 styles
保留其密钥。这意味着 TypeScript 会警告我们,例如styles.nonExistingStyle
,对于智能感知和发现错别字非常方便。特别是因为 style
属性接受 undefined
!
问:我们不能只用const styles = ... as const;
代替吗?
A:是的,这会起作用,但 TypeScript 不会验证您的样式,直到您将对象实际传递给 style
属性。此时,style
属性会报错,而使用上述解决方案,TypeScript 会在定义styles
时警告您,无论您是否使用它。 还有一个事实是styles
的类型将是一个非常复杂的对象,一旦您的对象中有多个(非微小)样式,智能感知(和 TypeScript 错误)将占据您的整个屏幕。与简单的 styleA: CSSProperties; styleB: CSSProperties; ...
截然不同。
问:我们不能只做const styles: styleA: CSSProperties = styleA: ... ;
吗?
A:是的,这同样有效,但它是双重工作。这是一个完全好的解决方案,现在它只取决于您喜欢哪种编码风格。如果您更喜欢查看例如const styles = MyStyles
而不是智能感知中的 const styles = styleA: CSSProperties; ...
。
【讨论】:
以上是关于在 Typescript、Webpack、React 项目中使用 css-in-js 时没有重载匹配此调用错误的主要内容,如果未能解决你的问题,请参考以下文章
从0开始的TypeScriptの五:webpack打包typescript
使用 npm 构建 webpack-typescript 库以用于其他 webpack-typescript 项目