考虑 Props 中的两种不同的函数变化
Account for two different function variations in Props
我不确定如何正确键入作为 props 传递的函数。
基本上可以有两种形状:
// Hoc1.tsx
import ChildComponent from "./ChildComponent";
const Hoc1 = () => {
const cancelResponse = async (agreement: boolean) => {
return mockCall(agreement);
};
return <ChildComponent cancelResponse={cancelResponse} />;
};
export default Hoc1;
和
// Hoc2.tsx
import ChildComponent from "./ChildComponent";
const Hoc2 = () => {
const cancelResponse = async (data: {
agreement: boolean;
shiftId: string;
userId: string;
}) => {
return mockCall(data);
};
return (
<ChildComponent
cancelResponse={cancelResponse}
cancelData={{ shiftId: "1", userId: "2" }}
/>
);
};
export default Hoc2;
现在我不确定我应该如何正确输入它。我尝试使用条件
这两个将不同的功能传递给所述 ChildComponent
type CancelResponseVariant<ArgumentVariant> = ArgumentVariant extends boolean
? boolean
: { agreement: boolean; shiftId: string; userId: string };
type Props = {
cancelResponse: <T>(arg: CancelResponseVariant<T>) => Promise<void>;
cancelData?: { shiftId: string; userId: string };
};
const ChildComponent = (props: Props) => {
const { cancelData, cancelResponse } = props;
const onCancelResponse = async (agreement: boolean) => {
if (cancelData) {
await cancelResponse({ agreement, ...cancelData });
} else {
await cancelResponse(agreement);
}
};
return <button onClick={async () => onCancelResponse(true)}>Example</button>;
};
export default ChildComponent;
这似乎接近解决方案,但并非完全如此。最后一次调用产生以下错误:
Argument of type 'boolean' is not assignable to parameter of type '{ agreement: boolean; shiftId: string; userId: string; }'.ts(2345)
并且在传递函数的 HoC 中产生以下错误:
Type '(agreement: boolean) => Promise' is not assignable to type '(arg: CancelResponseVariant) => Promise'.
Types of parameters 'agreement' and 'arg' are incompatible.
Type 'CancelResponseVariant' is not assignable to type 'boolean'.
Type 'boolean | { agreement: boolean; shiftId: string; userId: string; }' is not assignable to type 'boolean'.
Type '{ agreement: boolean; shiftId: string; userId: string; }' is not assignable to type 'boolean'.
知道我应该如何正确输入吗?
Note: Obviously I tried using a simple conditional union type as well
type Data = { agreement: boolean, userId: string, shiftId: string }
type Props = {
(agreement: boolean | Data) => Promise<void>
}
but that still throws an error inside the HoC
您可以在此处看到重现的错误:
PS:我知道这不是传递具有不同 arg 变体的函数的理想方式,但它是一个 5 年前的代码库,我需要迁移到打字稿,所以现在,我只是尽我所能。
因为在 cancelResponse
旁边的道具中有 cancelData
,所以你有一个受歧视的联合(即使 HOC 没有提供 cancelData
属性),所以你可以这样定义 Props
:
type Props =
// First variant
{
cancelResponse: (arg: boolean) => Promise<unknown>;
cancelData?: never;
}
|
// Second variant
{
cancelResponse: (arg: { agreement: boolean; shiftId: string; userId: string }) => Promise<unknown>;
cancelData: { shiftId: string; userId: string };
};
(稍后我将解释 Promise<unknown>
而不是 Promise<void>
,您可能不需要在实际代码中进行更改,但我做了例如。)
我们在第一个变体中需要 cancelData?: never;
,因为没有它,我们就没有完全可区分的联合。但我们将其设为可选,因此不需要它的 HOC 不会提供它(因此使用简单的 (agreement: boolean) => Promise<unknown>
签名)。
ChildComponent
根据 cancelData
:
找出要进行的调用
const ChildComponent = (props: Props) => {
const onCancelResponse = async (agreement: boolean) => {
if (props.cancelData) {
await props.cancelResponse({ agreement, ...props.cancelData });
} else {
await props.cancelResponse(agreement);
}
};
return <button onClick={async () => onCancelResponse(true)}>Example</button>;
};
这使得 Hoc1
和 Hoc2
都有效,并且不允许这种不正确的 Hoc3
:
// With an intentional error
const Hoc3 = () => {
const cancelResponse = async (agreement: boolean) => {
return mockCall(agreement);
};
return <ChildComponent cancelResponse={cancelResponse} cancelData={{shiftId: "1", userId: "2"}} />;
// ^−−−−− Error as desired, the provided `cancelResponse` has the wrong signature
};
关于示例中的 Promise<unknown>
而不是 Promise<void>
:那是因为在 Hoc1
和 Hoc2
中,您的代码正在执行 return mockCall(agreement);
和 mockCall
没有 return 类型注释,所以以 Promise<unknown>
结尾。如果 HOC 进行的实际调用具有 return 类型 Promise<void>
,则您可能不需要该更改。如果他们这样做了,那么您可以使用原来的 Promise<void>
、like this.
我不确定如何正确键入作为 props 传递的函数。
基本上可以有两种形状:
// Hoc1.tsx
import ChildComponent from "./ChildComponent";
const Hoc1 = () => {
const cancelResponse = async (agreement: boolean) => {
return mockCall(agreement);
};
return <ChildComponent cancelResponse={cancelResponse} />;
};
export default Hoc1;
和
// Hoc2.tsx
import ChildComponent from "./ChildComponent";
const Hoc2 = () => {
const cancelResponse = async (data: {
agreement: boolean;
shiftId: string;
userId: string;
}) => {
return mockCall(data);
};
return (
<ChildComponent
cancelResponse={cancelResponse}
cancelData={{ shiftId: "1", userId: "2" }}
/>
);
};
export default Hoc2;
现在我不确定我应该如何正确输入它。我尝试使用条件
这两个将不同的功能传递给所述 ChildComponent
type CancelResponseVariant<ArgumentVariant> = ArgumentVariant extends boolean
? boolean
: { agreement: boolean; shiftId: string; userId: string };
type Props = {
cancelResponse: <T>(arg: CancelResponseVariant<T>) => Promise<void>;
cancelData?: { shiftId: string; userId: string };
};
const ChildComponent = (props: Props) => {
const { cancelData, cancelResponse } = props;
const onCancelResponse = async (agreement: boolean) => {
if (cancelData) {
await cancelResponse({ agreement, ...cancelData });
} else {
await cancelResponse(agreement);
}
};
return <button onClick={async () => onCancelResponse(true)}>Example</button>;
};
export default ChildComponent;
这似乎接近解决方案,但并非完全如此。最后一次调用产生以下错误:
Argument of type 'boolean' is not assignable to parameter of type '{ agreement: boolean; shiftId: string; userId: string; }'.ts(2345)
并且在传递函数的 HoC 中产生以下错误:
Type '(agreement: boolean) => Promise' is not assignable to type '(arg: CancelResponseVariant) => Promise'. Types of parameters 'agreement' and 'arg' are incompatible. Type 'CancelResponseVariant' is not assignable to type 'boolean'. Type 'boolean | { agreement: boolean; shiftId: string; userId: string; }' is not assignable to type 'boolean'. Type '{ agreement: boolean; shiftId: string; userId: string; }' is not assignable to type 'boolean'.
知道我应该如何正确输入吗?
Note: Obviously I tried using a simple conditional union type as well
type Data = { agreement: boolean, userId: string, shiftId: string } type Props = { (agreement: boolean | Data) => Promise<void> }
but that still throws an error inside the HoC
您可以在此处看到重现的错误:
PS:我知道这不是传递具有不同 arg 变体的函数的理想方式,但它是一个 5 年前的代码库,我需要迁移到打字稿,所以现在,我只是尽我所能。
因为在 cancelResponse
旁边的道具中有 cancelData
,所以你有一个受歧视的联合(即使 HOC 没有提供 cancelData
属性),所以你可以这样定义 Props
:
type Props =
// First variant
{
cancelResponse: (arg: boolean) => Promise<unknown>;
cancelData?: never;
}
|
// Second variant
{
cancelResponse: (arg: { agreement: boolean; shiftId: string; userId: string }) => Promise<unknown>;
cancelData: { shiftId: string; userId: string };
};
(稍后我将解释 Promise<unknown>
而不是 Promise<void>
,您可能不需要在实际代码中进行更改,但我做了例如。)
我们在第一个变体中需要 cancelData?: never;
,因为没有它,我们就没有完全可区分的联合。但我们将其设为可选,因此不需要它的 HOC 不会提供它(因此使用简单的 (agreement: boolean) => Promise<unknown>
签名)。
ChildComponent
根据 cancelData
:
const ChildComponent = (props: Props) => {
const onCancelResponse = async (agreement: boolean) => {
if (props.cancelData) {
await props.cancelResponse({ agreement, ...props.cancelData });
} else {
await props.cancelResponse(agreement);
}
};
return <button onClick={async () => onCancelResponse(true)}>Example</button>;
};
这使得 Hoc1
和 Hoc2
都有效,并且不允许这种不正确的 Hoc3
:
// With an intentional error
const Hoc3 = () => {
const cancelResponse = async (agreement: boolean) => {
return mockCall(agreement);
};
return <ChildComponent cancelResponse={cancelResponse} cancelData={{shiftId: "1", userId: "2"}} />;
// ^−−−−− Error as desired, the provided `cancelResponse` has the wrong signature
};
关于示例中的 Promise<unknown>
而不是 Promise<void>
:那是因为在 Hoc1
和 Hoc2
中,您的代码正在执行 return mockCall(agreement);
和 mockCall
没有 return 类型注释,所以以 Promise<unknown>
结尾。如果 HOC 进行的实际调用具有 return 类型 Promise<void>
,则您可能不需要该更改。如果他们这样做了,那么您可以使用原来的 Promise<void>
、like this.