如何用样式化组件和TypeScript来包装Ant Design?

时间:2018-10-08 14:45:37

标签: typescript antd styled-components

我想用样式化的组件来包装我的蚂蚁设计组件,我知道这是可能的(https://gist.github.com/samuelcastro/0ff7db4fd54ce2b80cd1c34a85b40c08),但是我很难用TypeScript做到这一点。

这是我到目前为止所拥有的:

import { Button as AntButton } from 'antd';
import { ButtonProps } from 'antd/lib/button/button';
import styledComponents from 'styled-components';

interface IButtonProps extends ButtonProps {
   customProp: string;
}

export const Button = styledComponents<IButtonProps>(AntButton)`
  // any custom style here
`;

如您所见,我正在使用as any定义我的ant-design按钮以使其起作用,否则我会得到一些不兼容的类型,例如:

Argument of type 'typeof Button' is not assignable to parameter of
type 'ComponentType<IButtonProps>'.

Type 'typeof Button' is not assignable to type
'StatelessComponent<IButtonProps>'.

Types of property 'propTypes' are incompatible.

 Property 'customProp' is missing in type '{ 
    type: Requireable<string>; 
    shape: Requireable<string>; 
    size: Requireable<string>; 
    htmlType: Requireable<string>; 
    onClick: ...
    etc
 }

谢谢。

解决方案:

import { Button as AntButton } from 'antd';
import { NativeButtonProps } from 'antd/lib/button/button';
import * as React from 'react';
import styledComponents from 'styled-components';

export const Button = styledComponents<NativeButtonProps>(props => <AntButton {...props} />)`
    // custom-props
`;

5 个答案:

答案 0 :(得分:2)

问题的根源似乎是styled-components希望内部组件(AntButton)接受 all 指定接口(IButtonProps中的道具),但AntButton不接受customProp。要解决此问题,请遵循文档this section中的最后一个示例,并在调用customProp之前使用无状态功能组件删除AntButton

export const Button = styledComponents<IButtonProps>(
  ({ customProp, ...rest }) => <AntButton {...rest} />)`
  // any custom style here
`;

答案 1 :(得分:2)

上述解决方案对我不起作用,尽管可以解决。

const Button = styled((props: NativeButtonProps) => <AntButton {...props} />)``;

答案 2 :(得分:2)

我找到了这个古老的问题,并尝试以一种简单的方式解决:

import React from 'react';
import styled from 'styled-components';
import { Card } from 'antd';
import { CardProps } from 'antd/lib/card';

export const NewCard: React.FunctionComponent<CardProps> = styled(Card)`
  margin-bottom: 24px;
`;

没有渲染道具:D

如果只需要将一个组件包装为功能组件,那么就可以了。但是您将丢失类组件的属性,例如Card.Meta

有一种解决方法:

import React from 'react';
import styled from 'styled-components';
import { Card } from 'antd';
import { CardProps } from 'antd/lib/card';

export const NewCard: typeof Card = styled(Card)<CardProps>`
  margin-bottom: 24px;
` as any;

一切(也许是XD)都可以作为原始的Antd组件;)

答案 3 :(得分:2)

我的代码在这里。这就是工作。


import React from 'react';
import { Button as AntButton } from 'antd';
import { ButtonProps } from 'antd/lib/button/button';
import styled from 'styled-components';

const Container = styled.div`
  font-size: 20px;
`;


const Button: React.FunctionComponent<ButtonProps> = styled(AntButton)`
  margin-top: 24px;
  margin-left: 30px;
`;

export default function Home() {
  return (
    <Container>
      Hello World
      <Button type="primary">test</Button>
    </Container>
  );
}



答案 4 :(得分:0)

index.tsx(按钮组件)

import { Button as AntButton } from 'antd'
import { NativeButtonProps } from 'antd/lib/button/button'
import 'antd/lib/button/style/css'
import * as React from 'react'
import styledComponents from 'styled-components'
import * as colours from '../colours'

const getColour = (props: any) =>
  props.status === 'green'
    ? colours.STATUS_GREEN
    : props.status === 'red'
      ? colours.STATUS_RED
      : props.type === 'primary'
        ? colours.PRIMARY
        : colours.WHITE

export interface ButtonProps extends NativeButtonProps {
  status?: string
}

export default styledComponents((props: ButtonProps) => <AntButton {...props} />)`
  &:focus,
  &:hover
  & {
    background-color: ${getColour};
    border-color: ${getColour};
  }
`
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>

import React from 'react'
import Button, { ButtonProps } from './index'

interface ButtonAsyncSingleSuccessProps extends ButtonProps {
  clickFunc: any, // (...args: any[]) => Promise<any>
  labelLoading: string,
  labelReady: string,
  labelSuccess: string,
}

interface ButtonAsyncSingleSuccessState {
  label: string,
  loading: boolean,
  status: string
}

export default class ButtonAsyncSingleSuccess extends React.Component<
  ButtonAsyncSingleSuccessProps,
  ButtonAsyncSingleSuccessState
> {
  constructor (props: any) {
    super(props)
    this.state = {
      label: props.labelReady,
      loading: false,
      status: ''
    }
  }
  public clickHandler (event: any) {
    const { labelLoading, labelReady, labelSuccess, clickFunc } = this.props
    this.setState({
      label: labelLoading,
      loading: true,
      status: ''
    })
    clickFunc(event)
      .then(() => {
        this.setState({
          label: labelSuccess,
          loading: false,
          status: 'green'
        })
      })
      .catch(() => {
        this.setState({
          label: labelReady,
          loading: false,
          status: 'red'
        })
      })
  }
  public render () {
    const {
      labelLoading,
      labelReady,
      labelSuccess,
      clickFunc,
      ...props
    } = this.props
    const { label, loading, status } = this.state
    if (status === 'red') {
      setTimeout(() => this.setState({ status: '' }), 1000) // flash red
    }
    return (
      <Button
        {...props}
        loading={loading}
        status={status}
        onClick={(e) => this.clickHandler(e)}
      >
        {label}
      </Button>
    )
  }
}