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
我知道我可以将propTypes
替换为interface
interface Props {
name: string
}
但是,TypeScript抱怨我未声明className
。问题是,理想情况下,我想将interface
用作开发人员可以提供的道具规范,而不必声明className
或theme
之类的道具,这些道具由styled-components
之类的库。
如何正确地将此组件转换为TypeScript?
答案 0 :(得分:4)
这是将样式化组件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.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
类型或特定组件类型时,它应该可以正常工作。 ?
答案 1 :(得分:2)
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;
根据样式化的组件TypeScript docs:定义组件时,您需要在Props界面中将className标记为可选
答案 2 :(得分:0)
这里发生了很多事情。
props.theme不会正确键入,除非您将Theme的内部类型扩展到这样的位置。...
declare module "styled-components" {
/* tslint:disable */
export interface DefaultTheme extends YourThemeInterfaceType {}
}
如果您正确地遵循了扩充文档,但是如果您不能只是创建一个styled-components.d.ts文件,并将其更改为tsconfig,则会将props.theme的类型更改为YourThemeInterfaceType。
"include": [
"src/**/*"
],
接下来,您需要使用参数的类型来知道“名称”是一个字符串,并且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.
希望这会有所帮助。
编辑:原型在打字稿中也没有用。