英文:
React & TypeScript - Conditional argument type if props is present
问题
在React中,我正在尝试根据组件中是否传递了一个属性来设置函数参数的条件类型。
以下是示例,我有这个组件:
const DatePicker = ({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: (value: Dayjs | { [x: string]: Dayjs }) => void;
value: Dayjs;
objectKey?: string;
}) => JSX.Element
我想要做的是,如果"objectKey"作为属性传递了,那么函数handleDateChange中"value"参数的类型将是{ [x: string]: Dayjs },否则它将是value: Dayjs。
有人知道如何实现这个吗?
英文:
In react I'm trying to set a conditional type in a function argument depending if a prop is pass in the component.
Here is the example, I have this component:
const DatePicker = ({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: (value: Dayjs | { [x: string]: Dayjs }) => void;
value: Dayjs;
objectKey?: string;
}) => JSX
What I want to do is that, if "objectKey" is pass as props than the type of the paremeter "value" in the function handleDateChange would be { [x: string]: Dayjs }, otherwise it would be value: Dayjs.
Does anyone have an idea of how to make this?
答案1
得分: 2
你可以使用函数重载来实现类似这样的功能。
// 第一个重载签名
function DatePicker({
handleDateChange,
value,
}: {
handleDateChange: (value: Dayjs) => void;
value: Dayjs;
}): JSX;
// 第二个重载签名
function DatePicker({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: (value: { [x: string]: Dayjs }) => void;
value: Dayjs;
objectKey?: string;
}): JSX;
// 实现部分
function DatePicker({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: ((value: Dayjs) => void) | ((value: { [x: string]: Dayjs }) => void);
value: Dayjs;
objectKey?: string;
}) {
// ...
}
使用这种方法,DatePicker
只能根据你的定义来进行调用,但实现部分不会知道 handleDateChange
和 objectKey
之间的关联,因此仍然需要显式处理。
不知道 DatePicker
的任何详细信息,我认为最好只使用一个签名,让父组件进行更改以适应 DatePicker
,而不是让 DatePicker
处理来自其父组件的特殊情况。
英文:
You can achieve something like this with function overloads.
// first overload signature
function DatePicker({
handleDateChange,
value,
}: {
handleDateChange: (value: Dayjs) => void;
value: Dayjs;
}): JSX;
// second overload signature
function DatePicker({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: (value: { [x: string]: Dayjs }) => void;
value: Dayjs;
objectKey?: string;
}): JSX;
// implementation
function DatePicker({
handleDateChange,
value,
objectKey,
}: {
handleDateChange: ((value: Dayjs) => void) | ((value: { [x: string]: Dayjs }) => void);
value: Dayjs;
objectKey?: string;
}) {
// ...
}
With this approach DatePicker
can only be called according to your definition, however the implementation won't know the correlation between handleDateChange
and objectKey
so you still need to handle that explicitly.
Without knowing any details of DatePicker
I think it would be better to only use one signature and let the parent component make changes to fit DatePicker
instead of having DatePicker
handle special cases from it's parents.
答案2
得分: 1
以下类型应该能够满足您的需求,使用联合类型和交叉类型:
type DatePickerProps = {
value: Dayjs;
} & ({
objectKey?: undefined;
handleDateChange: (value: Dayjs) => void;
} | {
objectKey: string;
handleDateChange: (value: { [x: string]: Dayjs }) => void;
});
解释:
- 由于
value
始终是类型的一部分,我们首先添加它以将其排除在外,并且不重复定义它。 - 然后,我们将这部分与根据您的规则可能变化的两种情况的联合类型(
|
)相交(&
),具体而言: handleDateChange
的签名根据objectKey
的类型是string
还是undefined
(未设置)而变化。- 我们以不同方式定义
objectKey
(首先带?
,然后没有)是因为我们希望让TypeScript知道在未设置时它是完全可省略的。
您可以简单地将其分配给props参数对象:
const DatePicker = ({ handleDateChange, value, objectKey }: DatePickerProps) => {
// ...
}
英文:
The following type should do what you are interested in, using Unions and Intersections:
type DatePickerProps = {
value: Dayjs;
} & ({
objectKey?: undefined;
handleDateChange: (value: Dayjs) => void;
} | {
objectKey: string;
handleDateChange: (value: { [x: string]: Dayjs }) => void;
});
Explanation:
- Since
value
is always part of the type, we add it first to get it out of the way, and so that we don't duplicate it. - Then we intersect (
&
) that part with the union (|
) of the two situations that can vary according to your rules, specifically: - The signature of
handleDateChange
varies based on whether the type ofobjectKey
isstring
orundefined
(not set). - We define
objectKey
differently (first with?
, then without) because we want to let TypeScript know it is completely omittable when not set.
You can simply assign it to the props parameter object:
const DatePicker =
({handleDateChange, value, objectKey}: DatePickerProps) =>
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论