Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Reactjs React和Typescript功能组件可以是3个接口中的1个_Reactjs_Typescript - Fatal编程技术网

Reactjs React和Typescript功能组件可以是3个接口中的1个

Reactjs React和Typescript功能组件可以是3个接口中的1个,reactjs,typescript,Reactjs,Typescript,我正在尝试创建一个组件,它可以使用3个接口中的1个,能够根据传递给它的道具来确定什么接口 interface CommonProps { label: string; icon?: React.ComponentType; role?: string; } interface ButtonProps extends CommonProps { handleOnClick: () => void; selected?: boolean; largeVariant?:

我正在尝试创建一个组件,它可以使用3个接口中的1个,能够根据传递给它的道具来确定什么接口

interface CommonProps {
  label: string;
  icon?: React.ComponentType;
  role?: string;
}

interface ButtonProps extends CommonProps {
  handleOnClick: () => void;
  selected?: boolean;
  largeVariant?: boolean;
}

interface LinkProps {
  to: string;
  openInNewTab?: boolean;
}

interface HrefProps {
  href: string;
  openInNewTab?: boolean;
}

const Button: React.FC<ButtonProps | LinkProps | HrefProps> = props => {
  const { label, handleOnClick, to, href, icon, openInNewTab } = props;
  if (to || href) {
    const Component = to ? Link : 'a';
    return (
      <StyledButton
        component={Component}
        target={openInNewTab ? '_blank' : undefined}
        onMouseDown={(e: any) => {
          href && pushMatomoExternalLink(e, href);
        }}
        {...props}
      >
        {icon && <StyledIcon icon={icon} />}
        {label}
      </StyledButton>
    );
  }
  return (
    <StyledButton onClick={handleOnClick} {...props}>
      {icon && <StyledIcon icon={icon} />}
      {label}
    </StyledButton>
  );
};
接口公共道具{
标签:字符串;
图标?:React.ComponentType;
角色?:字符串;
}
界面按钮按钮扩展了公共道具{
点击:()=>作废;
选择?:布尔值;
大变型?:布尔型;
}
接口链接道具{
到:字符串;
openInNewTab?:布尔值;
}
接口HrefProps{
href:string;
openInNewTab?:布尔值;
}
常量按钮:React.FC=props=>{
const{label,handleOnClick,to,href,icon,openInNewTab}=props;
如果(到| | href){
常量分量=到?链接:“a”;
返回(
{
href&&pushmatomoExternalink(e,href);
}}
{…道具}
>
{图标&&}
{label}
);
}
返回(
{图标&&}
{label}
);
};
期望的行为,包括我期望看到的错误

<Button label="View Report" handleOnClick={action('BUTTON CLICKED')} />

将推断接口是按钮操作

<Button label="View Report" selected />

类型脚本错误:类型中缺少属性“handleOnClick”{ label:string;selected:boolean;}但在类型“buttonrops”中是必需的


将推断接口将是LinkProps或HrefProps

属性“to”在类型“{label:string;openInNewTab:boolean;}”中丢失,但在类型“LinkProps”中是必需的

属性“href”在类型“{label:string;openInNewTab:boolean;}”中丢失,但在类型“HrefProps”中是必需的



会推断接口是HrefProps

我不明白你的问题是什么;如果我获取的是您的确切代码,除了
按钮的错误实现(假设a不需要此实现),编译器会准确地给出您希望看到的错误

declare const Button: React.FC<ButtonProps | LinkProps | HrefProps>;
<Button label="View Report" handleOnClick={console.log} />;
// okay

<Button label="View Report" selected />; 
// Property 'handleOnClick' is missing in type '{ label: string; selected: true; }' 
// but required in type 'ButtonProps'.(2322)

<Button label="View Report" openInNewTab />;
// Property 'href' is missing in type '{ label: string; openInNewTab: true; }' 
// but required in type 'HrefProps'.(2322)

<Button label="View Report" href="/" openInNewTab />;
// okay
declare const按钮:React.FC;
;
//好的
; 
//类型“{label:string;selected:true;}”中缺少属性“handleOnClick”
//但在“按钮操作”类型中是必需的。(2322)
;
//类型“{label:string;openInNewTab:true;}”中缺少属性“href”
//但在“HrefProps”类型中是必需的。(2322)
;
//好的
如果这不是您期望的,或者问题实际上与
按钮的实现有关,请编辑您的问题,以指定问题是什么,包括一个可复制的示例,该示例准确显示您看到的内容以及它与您期望看到的内容的差异。祝你好运


一个可能的解决方案是使用检查传递的道具类型。一个类型守卫应该有一个逻辑来找出它得到了什么类型的道具。在下面的代码中,
propsIsButtonProps
propsIsLinkProps
propsIsHrefProps
是类型保护

我已经简化了您的代码以展示主要思想

function propsIsButtonProps (props: any): props is ButtonProps {
  return props.selected !== undefined;
}
function propsIsLinkProps (props: any): props is LinkProps {
  return props.to !== undefined;
}
function propsIsHrefProps (props: any): props is HrefProps {
  return props.href !== undefined;
}

export const Button: React.FC<ButtonProps | LinkProps | HrefProps> = props => {
  if (propsIsLinkProps(props) || propsIsHrefProps(props)) {
    const Component = propsIsLinkProps(props) ? 'div' : 'a';
    return (
      <Component
        target={props.openInNewTab ? '_blank' : undefined}
        onMouseDown={(e: any) => {
          propsIsHrefProps(props) && pushMatomoExternalLink(e, props.href);
        }}
        {...props}
      >
        {props.label}
      </Component>
    );
  }
  return (
    <button onClick={props.handleOnClick} {...props}>
      {props.label}
    </button>
  );
};
功能propsIsButtonProps(props:any):props是ButtonProps{
返回道具。已选择!==未定义;
}
功能道具LinkProps(道具:任意):道具为LinkProps{
返回props.to!==未定义;
}
函数propsIsHrefProps(props:any):props是HrefProps{
return props.href!==未定义;
}
导出常量按钮:React.FC=props=>{
if(道具链接道具(道具)| |道具重铺道具(道具)){
const Component=propsIsLinkProps(props)?“div”:“a”;
返回(
{
propsIsHrefProps(props)和pushMatomoExternalLink(e,props.href);
}}
{…道具}
>
{props.label}
);
}
返回(
{props.label}
);
};

工作演示是

你说的是函数重载,对吗?这可以很容易地用C/C++语言来完成,但是用打字稿很难。这是因为在最后typescript代码转换成JavaScript和in-JavaScript函数重载是不可能的

这里有一个可能的解决方案

interface CommonProps {
  label: string;
  icon?: string;
  role?: string;
}

export interface ButtonProps extends CommonProps {
  kind: "button-props";
  handleOnClick: () => void;
  selected?: boolean;
  largeVariant?: boolean;
}

export interface LinkProps {
  kind: "link-props";
  to: string;
  openInNewTab?: boolean;
}

export interface HrefProps {
  kind: "href-props";
  href: string;
  openInNewTab?: boolean;
}

type Types = HrefProps | LinkProps | ButtonProps ;

const Button : React.FC<Types> = props => {
    switch(props.kind){
        case "button-props" :
            // some code
        case "href-props" :
            // some code
        case "link-props" :
            // some code
        default :
            return;
    }
}
接口公共道具{
标签:字符串;
图标?:字符串;
角色?:字符串;
}
导出接口按钮操作扩展了CommonProps{
种类:“按钮道具”;
点击:()=>作废;
选择?:布尔值;
大变型?:布尔型;
}
导出接口链接道具{
种类:“链接道具”;
到:字符串;
openInNewTab?:布尔值;
}
导出接口HrefProps{
种类:“href道具”;
href:string;
openInNewTab?:布尔值;
}
类型类型=HrefProps |链接支柱|按钮按钮;
常量按钮:React.FC=props=>{
开关(道具类){
案例“按钮道具”:
//一些代码
案例“href props”:
//一些代码
案例“链接道具”:
//一些代码
违约:
返回;
}
}
现在在父组件中

import { ButtonProps, LinkProps, HrefProps } from './Button.component.ts';

function Parent = (props) => {
   const propsToChild : ButtonProps = {// data object with type ButtonProps}
   return (
     <Button {...propsToChild}/>
   )
}
从“/Button.component.ts”导入{ButtonProps,LinkProps,HrefProps};
函数父项=(道具)=>{
const-propsToChild:ButtonProps={//类型为ButtonProps的数据对象}
返回(
)
}

请考虑编辑代码以构成一个可以落入独立IDE的代码,以便其他人可以看到您的问题。现在我没有
Link
StyledButton
的定义,所以我不确定我的建议是否适用于您。我也不明白你所说的“推断”是什么意思;您希望编译器具体在哪里推断接口?编译器在这里的行为在我看来是合理的;你能详细说明一下你的期望和正在发生的事情吗?谢谢你的建议。下班后我将对示例进行一些更改。
interface CommonProps {
  label: string;
  icon?: string;
  role?: string;
}

export interface ButtonProps extends CommonProps {
  kind: "button-props";
  handleOnClick: () => void;
  selected?: boolean;
  largeVariant?: boolean;
}

export interface LinkProps {
  kind: "link-props";
  to: string;
  openInNewTab?: boolean;
}

export interface HrefProps {
  kind: "href-props";
  href: string;
  openInNewTab?: boolean;
}

type Types = HrefProps | LinkProps | ButtonProps ;

const Button : React.FC<Types> = props => {
    switch(props.kind){
        case "button-props" :
            // some code
        case "href-props" :
            // some code
        case "link-props" :
            // some code
        default :
            return;
    }
}
import { ButtonProps, LinkProps, HrefProps } from './Button.component.ts';

function Parent = (props) => {
   const propsToChild : ButtonProps = {// data object with type ButtonProps}
   return (
     <Button {...propsToChild}/>
   )
}