带有样式组件的 TypeScript
Posted
技术标签:
【中文标题】带有样式组件的 TypeScript【英文标题】:TypeScript with styled-components 【发布时间】:2019-08-20 02:43:04 【问题描述】:TypeScript 新手在这里。我有一个使用styled-components
的组件,我想将其转换为TypeScript
。
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
const propTypes =
name: PropTypes.string.isRequired // https://material.io/tools/icons/?style=baseline
const Icon = styled((name, className, ...props) => <i className=`material-icons $className` ...props>name</i>)`
font-size: $props => props.theme.sizeLarger;
`
Icon.propTypes = propTypes
export default Icon
我知道我可以用interface
替换我的propTypes
interface Props
name: string
但是,TypeScript 抱怨我未声明 className
。问题是,理想情况下,我希望将interface
用作开发人员可以提供的一种道具规范,而不必声明由styled-components
等库注入的className
或theme
之类的道具。
如何正确将此组件转换为 TypeScript?
【问题讨论】:
【参考方案1】:import React from "react";
import styled from "styled-components";
interface Props
name: string;
className?: string;
const NonStyledIcon: React.SFC<Props> = ( name, className, ...props ) => (
<i className=`material-icons $className` ...props>
name
</i>
);
const Icon = styled(NonStyledIcon)`
font-size: $props => props.theme.sizeLarger;
`;
export default Icon;
根据 styled-components TypeScript docs:定义组件时,您需要在 Props 界面中将 className 标记为可选
【讨论】:
嗯...声明className
感觉既多余又具有误导性,不是吗?这告诉组件的潜在用户他们可能会设置一个className
属性,在这种情况下组件不会按预期工作,对吧?
我会说这是一个有效的反对意见,但它仍然是官方的做法
这很烦人。我认为在增加样式时应该增加界面。
谢谢您-这个答案很完整,对我帮助很大。干得好!【参考方案2】:
这是一个使用 Styled Components v5 和 React Native 的综合方法,它也适用于普通的 React。如果您没有使用主题,可以跳到底部的StyledProps
部分。
定义您的主题类型。
// MyTheme.ts
export type MyTheme =
colors:
primary: string;
background: string;
;
;
在您的主题上使用类型。
// themes.ts
export const LightTheme: MyTheme =
colors:
primary: 'white',
background: 'white',
,
;
export const DarkTheme: MyTheme =
colors:
primary: 'grey',
background: 'black',
,
;
使用declaration merging 将 MyTheme 类型“合并”到 Styled Components 默认主题中。
// styled.d.ts
import 'styled-components';
import MyTheme from '../src/themes/MyTheme';
declare module 'styled-components'
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface DefaultTheme extends MyTheme
好的,很酷。 theme
属性输入正确。
组件本身呢?
将您的特定组件道具包装在 StyledProps
类型中。
import StyledProps from 'styled-components';
import styled from 'styled-components/native';
type MyViewProps = StyledProps<
backgroundColor?: string;
isAlert?: boolean;
>;
const MyView = styled.View(
(props: MyViewProps) => `
background-color: $props.backgroundColor || props.theme.colors.background;
color: $props.isAlert ? red : props.theme.colors.primary
`,
);
在此示例中,props.backgroundColor
和 props.theme.colors.background
都将自动完成。当您更新 MyTheme
类型或特定组件类型时,它应该可以正常工作。 ?
【讨论】:
它实际上帮助了我很多!谢谢 用户注意:将文件命名为styled-components.d.ts
会导致它完全覆盖@types 定义。相反,您应该将其命名为 styled.d.ts
或将声明与其他全局类型放在 index.d.ts
中【参考方案3】:
这里发生了很多事情。
props.theme 不会正确输入,除非您在这样的地方增加了 Theme 的内部类型......
declare module "styled-components"
/* tslint:disable */
export interface DefaultTheme extends YourThemeInterfaceType
这会将 props.theme 的类型更改为 YourThemeInterfaceType,如果您正确遵循扩充文档,但如果您不能只创建一个 styled-components.d.ts 文件并将其添加到您的 tsconfig。
"include": [
"src/**/*"
],
接下来你需要参数的类型来知道“name”是一个字符串,而className也是我假设一个可选的字符串来做到这一点只需将上面的内容重写为这个。
interface IIconProps
name: string;
className?: string;
;
const Icon = styled((name, className, ...props: IIconProps) => <i className=`material-icons $className` ...props>name</i>)`
font-size: $props => props.theme.sizeLarger;
`;
const test = <Icon name="xyz" className="xyz"/> // passes typecheck.
希望这会有所帮助。
编辑:在打字稿中,proptypes 也是无用的。
【讨论】:
以上是关于带有样式组件的 TypeScript的主要内容,如果未能解决你的问题,请参考以下文章