问题
TypeScript newbie here. I have a below component using styled-components
that I would like to convert to 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
I know I can replace my propTypes
with an interface
interface Props {
name: string
}
However, TypeScript complains that I leave className
undeclared. The thing is, I would ideally like to use the interface
as a sort of spec for props that a developer can provide, without having to declare props like className
or theme
which are injected by libraries like styled-components
.
How do I properly convert this component to 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;
As per the styled-components TypeScript docs: when defining a component you will need to mark className as optional in your Props interface
回答2:
There are many things happening here.
props.theme is not going to typed properlly unless you have the internal type for Theme augmented somewhere like this....
declare module "styled-components" {
/* tslint:disable */
export interface DefaultTheme extends YourThemeInterfaceType {}
}
This will change the type of props.theme to YourThemeInterfaceType, if you follow the augmentation documentation properlly but if you can't just create a styled-components.d.ts file and this to your tsconfig.
"include": [
"src/**/*"
],
Next you need the type of the arguments to know "name" is a string, and className is also i'm assuming a optional string to do this just rewrite the above to this.
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.
Hope this helps.
EDIT: also proptypes are usless in typescript.
回答3:
Here's a comprehensive approach using Styled Components v5 with React Native that will work with plain React as well. If you're not using a theme you can skip to the StyledProps
section at the bottom.
Define your theme type.
// MyTheme.ts export type MyTheme = { colors: { primary: string; background: string; }; };
Use the type on your themes.
// themes.ts export const LightTheme: MyTheme = { colors: { primary: 'white', background: 'white', }, }; export const DarkTheme: MyTheme = { colors: { primary: 'grey', background: 'black', }, };
Use declaration merging to "merge" the MyTheme type into Styled Components default theme.
// 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 {} }
OK, cool. The theme
prop is correctly typed.
What about the components themselves?
Wrap your specific component props in the
StyledProps
type.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} `, );
In this example both props.backgroundColor
and props.theme.colors.background
will auto-complete. When you update MyTheme
type or the specific component type it should just work. 👍
来源:https://stackoverflow.com/questions/55412662/typescript-with-styled-components