使用带有 props 和 typescript 的样式组件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47077210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:00:28  来源:igfitidea点击:

Using styled components with props and typescript

javascriptreactjstypescriptjsxstyled-components

提问by Ilja

I'm trying to integrate typescript into our project and so far I stumbled upon one issue with styled-componentslibrary

我正在尝试将打字稿集成到我们的项目中,到目前为止我偶然发现了样式组件库的一个问题

Consider this component

考虑这个组件

import * as React from "react";
import styled from "styled-components/native";
import { TouchableOpacity } from "react-native";

// -- types ----------------------------------------------------------------- //
export interface Props {
  onPress: any;
  src: any;
  width: string;
  height: string;
}

// -- styling --------------------------------------------------------------- //
const Icon = styled.Image`
  width: ${(p: Props) => p.width};
  height: ${(p: Props) => p.height};
`;

class TouchableIcon extends React.Component<Props> {
  // -- default props ------------------------------------------------------- //
  static defaultProps: Partial<Props> = {
    src: null,
    width: "20px",
    height: "20px"
  };

  // -- render -------------------------------------------------------------- //
  render() {
    const { onPress, src, width, height } = this.props;
    return (
      <TouchableOpacity onPress={onPress}>
        <Icon source={src} width={width} height={height} />
      </TouchableOpacity>
    );
  }
}

export default TouchableIcon;

Following line throws 3 errors, that are same in nature <Icon source={src} width={width} height={height} />

以下行抛出 3 个错误,本质上是相同的 <Icon source={src} width={width} height={height} />

Type {source: any; width: string; height: string;} is not assignable to type IntrinsicAttributes ... Property 'onPress' is missing in type {source: any; width: string; height: string;}

输入{来源:任何;宽度:字符串;高度:字符串;} 不可分配到类型 IntrinsicAttributes ... {source: any; 类型中缺少属性“onPress” 宽度:字符串;高度:字符串;}

Not entirely sure what this is and how to fix it, do I somehow need to declare these on Iconor something of this sort?

不完全确定这是什么以及如何解决它,我是否需要以某种方式声明这些Icon或类似的东西?

EDIT:typescript v2.6.1, styled-components v2.2.3

编辑:打字稿 v2.6.1,样式组件 v2.2.3

采纳答案by juandemarco

This answer is outdated, the most current answer is here: https://stackoverflow.com/a/52045733/1053772

这个答案已经过时了,最新的答案在这里:https: //stackoverflow.com/a/52045733/1053772

As far as I can tell there is no official way (yet?) to do this, but you can solve it with a bit of trickery. First, create a withProps.tsfile with the following content:

据我所知,目前还没有官方的方法(还?)来做到这一点,但你可以通过一些技巧来解决它。首先,创建一个withProps.ts包含以下内容的文件:

import * as React from 'react'
import { ThemedStyledFunction } from 'styled-components'

const withProps = <U>() => <P, T, O>(fn: ThemedStyledFunction<P, T, O>) =>
    fn as ThemedStyledFunction<P & U, T, O & U>

export { withProps }

Now, inside your .tsxfiles, use it like this:

现在,在您的.tsx文件中,像这样使用它:

// ... your other imports
import { withProps } from './withProps'

export interface IconProps {
  onPress: any;
  src: any;
  width: string;
  height: string;
}

const Icon = withProps<IconProps>()(styled.Image)`
  width: ${(p: IconProps) => p.width};
  height: ${(p: IconProps) => p.height};
`;

And you should be good to go. It's definitely notideal and hopefully there will be a way to provide generics to template literals soon in TS, but I guess that for now this is your best option.

你应该很高兴去。这绝对不是理想的,希望很快就会有一种方法可以在 TS 中为模板文字提供泛型,但我想现在这是您最好的选择。

Credit is given where credit is due: I copypasted this from here

在信用到期时给予信用:我从这里复制粘贴

回答by elnygren

There have been some recent developments and with a new version of Typescript (eg. 3.0.1) and styled-components (eg. 3.4.5) there's no need for a separate helper. You can specify the interface/type of your props to styled-components directly.

最近有了一些发展,有了新版本的 Typescript(例如 3.0.1)和样式组件(例如 3.4.5),就不需要单独的帮助程序了。您可以直接为样式组件指定道具的接口/类型。

interface Props {
  onPress: any;
  src: any;
  width: string;
  height: string;
}

const Icon = styled.Image<Props>`
  width: ${p => p.width};
  height: ${p => p.height};
`;

and if you want to be more precise and ignore the onPress

如果你想更精确并忽略 onPress

const Icon = styled.Image<Pick<Props, 'src' | 'width' | 'height'>>`
  width: ${p => p.width};
  height: ${p => p.height};
`;

回答by thul

I'm struggling through this myself, but I think the problem is that you are using the Props interface inside the styled component. Try creating another interface with just the image props and use that in your styled component:

我自己也在为此苦苦挣扎,但我认为问题在于您在样式组件中使用了 Props 界面。尝试仅使用图像道具创建另一个界面,并在您的样式组件中使用它:

import * as React from "react";
import styled from "styled-components/native";
import { TouchableOpacity } from "react-native";

// -- types ----------------------------------------------------------------- //
export interface Props {
  onPress: any;
  src: any;
  width: string;
  height: string;
}


export interface ImageProps {
  src: string;
  width: string;
  height: string;
}

// -- styling --------------------------------------------------------------- //
const Icon = styled.Image`
  width: ${(p: ImageProps ) => p.width};
  height: ${(p: ImageProps ) => p.height};
`;

class TouchableIcon extends React.Component<Props> {
  // -- default props ------------------------------------------------------- //
  static defaultProps: Partial<Props> = {
    src: null,
    width: "20px",
    height: "20px"
  };

  // -- render -------------------------------------------------------------- //
  render() {
    const { onPress, src, width, height } = this.props;
    return (
      <TouchableOpacity onPress={onPress}>
        <Icon source={src} width={width} height={height} />
      </TouchableOpacity>
    );
  }
}

export default TouchableIcon;

Seems to work but I hate to have to duplicate those interfaces. Hopefully someone else can show the correct way or maybe embedding the ImageProps into Props?

似乎工作,但我讨厌必须复制这些接口。希望其他人可以展示正确的方式,或者可能将 ImageProps 嵌入到道具中?