Reactjs React和Typescript功能组件可以是3个接口中的1个
我正在尝试创建一个组件,它可以使用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?:
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}/>
)
}