我正在尝试为自定义输入组件设置一个类型,该类型将根据要显示的元素类型继承属性。本质上,逻辑是标题所陈述的
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 认为我正在使用GenericInputElementProps
和element='input'
,但没有考虑其他选项。我确信有办法解决这个问题,但我找不到我可以使用的模式。
如果你有类型A
、B
、C
、D
和E
,并且你想表示"A
和B
或C
或D
或E
"的东西,那么你可以通过将"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
) => {};
也许它看起来有点荒谬,但它工作得很好。