TypeScript Logic 难题 - A 和 B 或 C 或 D



我正在尝试为自定义输入组件设置一个类型,该类型将根据要显示的元素类型继承属性。本质上,逻辑是标题所陈述的

type A AND EITHER B or C or D or E

意思是始终应用 A,然后 B 或 C 或 D 或 E 紧随其后。这是我到目前为止所拥有的。

interface GenericInputElementProps {
id: string;
hidden: boolean;
label: string;
onInput: (
id: string,
value: string | number,
isValid: boolean
) => {
type: string;
value: string | number;
inputId: string;
isValid: boolean;
};
validators?: { type: string; configVal?: number }[];
initialValue?: {
initialValue: string;
initialValid: boolean;
};
}
type InputElementProps =
| (
| GenericInputElementProps
| {
element: 'input';
type: string;
placeholder: string;
errorText: string;
}
)
| {
element: 'textarea';
rows: number;
placeholder: string;
errorText: string;
}
| { element: 'number'; type: 'number' }
| { element: 'checkbox'; type: 'checkbox' }
| { element: 'select'; sizes: ISizes[] };

但这不起作用,因为 Typescript 认为我正在使用GenericInputElementPropselement='input',但没有考虑其他选项。我确信有办法解决这个问题,但我找不到我可以使用的模式。

如果你有类型ABCDE,并且你想表示"ABCDE"的东西,那么你可以通过将"and"变成交集,将"or">变成并集来实现, 喜欢:

type Okay = A & (B | C | D | E);
// type Okay = A & (B | C | D | E)

这些括号很重要,因为交集比 TypeScript 语法中的并集绑定得更紧密:

type Oops = A & B | C | D | E;
// type Oops = (A & B) | C | D | E

这意味着你应该做这样的事情:

type InputElementProps = GenericInputElementProps & (
{
element: 'input';
type: string;
placeholder: string;
errorText: string;
} | {
element: 'textarea';
rows: number;
placeholder: string;
errorText: string;
} | {
element: 'number'; type: 'number'
} | {
element: 'checkbox'; type: 'checkbox'
} | {
element: 'select'; sizes: ISizes[]
}
);

如果你想把它们分解成它们自己的接口,这取决于你:

interface TextElementProps {
element: 'input';
type: string;
placeholder: string;
errorText: string;
};
interface TextAreaElementProps {
element: 'textarea';
rows: number;
placeholder: string;
errorText: string;
};
interface NumberElementProps {
element: 'number';
type: 'number';
};
interface CheckboxElementProps {
element: 'checkbox';
type: 'checkbox';
};
interface SelectElementProps {
element: 'select';
sizes: ISizes[];
};
type InputElementProps = GenericInputElementProps & (
TextElementProps |
TextAreaElementProps |
NumberElementProps |
CheckboxElementProps |
SelectElementProps
);

操场链接到代码

这就是我最终所做的

interface GenericInputElementProps {
id: string;
hidden: boolean;
label: string;
onInput: (
id: string,
value: string | number,
isValid: boolean
) => {
type: string;
value: string | number;
inputId: string;
isValid: boolean;
};
validators?: { type: string; configVal?: number }[];
initialValue?: {
initialValue: string;
initialValid: boolean;
};
}
type TextElementProps = GenericInputElementProps & {
element: 'input';
type: string;
placeholder: string;
errorText: string;
};
type TextAreaElementProps = GenericInputElementProps & {
element: 'textarea';
rows: number;
placeholder: string;
errorText: string;
};
type NumberElementProps = GenericInputElementProps & {
element: 'number';
type: 'number';
};
type CheckboxElementProps = GenericInputElementProps & {
element: 'checkbox';
type: 'checkbox';
};
type SelectElementProps = GenericInputElementProps & {
element: 'select';
sizes: ISizes[];
};

然后

export const Input = (
props:
| TextElementProps
| TextAreaElementProps
| NumberElementProps
| CheckboxElementProps
| SelectElementProps
) => {};

也许它看起来有点荒谬,但它工作得很好。

相关内容

  • 没有找到相关文章

最新更新