最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - styled-system props typing with TypeScript - Stack Overflow

programmeradmin0浏览0评论

I'm using styled-system and one key of the library is to use the shorthand props to allow easy and fast theming.

I've simplified my component but here is the interesting part:

import React from 'react'
import styled from 'styled-components'
import { color, ColorProps } from 'styled-system'

const StyledDiv = styled('div')<ColorProps>`
  ${color}
`

const Text = ({ color }: ColorProps) => {
  return <StyledDiv color={color} />
}

I have an error on the color prop which says:

Type 'string | (string | null)[] | undefined' is not assignable to type 'string | (string & (string | null)[]) | undefined'.

I think that's because styled-system use the same naming as the native HTML attribute color and it conflicts.

How do I solve this?

I'm using styled-system and one key of the library is to use the shorthand props to allow easy and fast theming.

I've simplified my component but here is the interesting part:

import React from 'react'
import styled from 'styled-components'
import { color, ColorProps } from 'styled-system'

const StyledDiv = styled('div')<ColorProps>`
  ${color}
`

const Text = ({ color }: ColorProps) => {
  return <StyledDiv color={color} />
}

I have an error on the color prop which says:

Type 'string | (string | null)[] | undefined' is not assignable to type 'string | (string & (string | null)[]) | undefined'.

I think that's because styled-system use the same naming as the native HTML attribute color and it conflicts.

How do I solve this?

Share Improve this question asked Dec 10, 2018 at 18:20 KerumenKerumen 4,3412 gold badges20 silver badges34 bronze badges
Add a comment  | 

6 Answers 6

Reset to default 5

color seems to be declared in react's declaration file under HTMLAttributes - it's not exported.

I had to work around this by creating a custom prop

Example is using @emotion/styled but also works with styled-components

// component.js
import styled from '@emotion/styled';
import { style, ResponsiveValue } from 'styled-system';
import CSS from 'csstype';

const textColor = style({
  prop: 'textColor',
  cssProperty: 'color',
  key: 'colors'
});


type Props = {
  textColor?: ResponsiveValue<CSS.ColorProperty>
}

const Box = styled.div<Props>`
  ${textColor};
`

export default Box;
// some-implementation.js
import Box from '.';

const Page = () => (
  <Box textColor={['red', 'green']}>Content in a box</Box>
);

This seems to only happen when you pass the prop down from an ancestor/parent component to a custom component rather than directly to the "styled" component. I found a discussion about it in the styled-components GitHub issues. Following the thread from there there is discussion of utilising transient props and their ultimate inclusion in styled-components v5.1.

This however didn't seem to solve the problem completely in my case.

The problem appears to be due to the component in question returning an HTML div element and so it is extended correctly (by React.HTMLAttributes) to include color: string | undefined as a DOM attribute for that element. This is of course not compatible with ColorProps hence the error. Styled-components filters out a whitelist that includes color however this won't happen in your custom or HOC.

This can be resolved in a number of ways, but the cleanest seems to be adding as?: React.ElementType to your type definition.

In this case:

import React from 'react'
import styled from 'styled-components'
import { color, ColorProps } from 'styled-system'

interface Props extends ColorProps { as?: React.ElementType }

const StyledDiv = styled('div')<Props>`
  ${color}
`

const Text = ({ color }: Props) => {
  return <StyledDiv color={color} />
}

This way the extension by React.HTMLAttributes is replaced by React.ElementType and so there is no longer a conflict with the color DOM attribute.

This also solves problems with passing SpaceProps.

NOTE:

It appears styled-system has been unceremoniously abandoned. There are a few open issues about what is being used to replace it. My recommendation after a little deliberation is system-ui/theme-ui. It seems to be the closest direct replacement and has a few contributors in common with styled-system.

Instead of using ColorProps, try using color: CSS.ColorProperty (`import * as CSS from 'csstype'); Here is a gist showing how I'm creating some a typed "Box" primitive with typescript/styled-system: https://gist.github.com/chiplay/d10435c0962ec62906319e12790104d1

Good luck!

What I did was to use Typescript cast capabilities and keep styled-system logic intact. e.g.:

const Heading: React.FC<ColorProps> = ({ color, children }) => {
  return <HeadingContainer color={(color as any)} {...props}>{children}</HeadingContainer>;
};

Just to add to xuanlopez' answer - not sure what issue the 5.0.0 release specifically resolves - but using $color as the renamed prop rather than textColor designates it as a transient prop in styled components so as a prop it won't appear in the rendered DOM.

Building on Chris' answer, and using the latest docs on on custom props.

// core/constants/theme.ts
// Your globally configured theme file
export const theme = { colors: { primary: ['#0A43D2', '#04122B'] } }

// core/constants/styledSystem.ts
import {
  color as ssColor,
  ColorProps as SSColorProps,
  TextColorProps,
  compose,
  system,
} from 'styled-system'

// Styled-system patch for the color prop fixing "Types of property 'color' are incompatible"
// when appling props to component that extend ColorProps.
export interface ColorProps extends Omit<SSColorProps, 'color'> {
  textColor?: TextColorProps['color']
}

export const color = compose(
  ssColor,
  system({
    // Alias color as textColor
    textColor: {
      property: 'color',
      // This connects the property to your theme, so you can use the syntax shown below E.g "primary.0".
      scale: 'colors'
    }
  })
)

// components/MyStyledComponent.ts
import { color, ColorProps } from 'core/constants/styledSystem.ts'

interface MyStyledComponentProps extends ColorProps {}

export const MyStyledComponent = styled.div<MyStyledComponentProps>`
  ${color}
`

// components/MyComponent.ts
export const MyComponent = () => <MyStyledComponent textColor="primary.0">...

EDIT: updating to styled-components ^5.0.0 fixes this

https://github.com/styled-components/styled-components/blob/master/CHANGELOG.md#v500---2020-01-13

发布评论

评论列表(0)

  1. 暂无评论