推断打字稿函数参数
Infer typescript function arguments
鉴于以下情况
const action1 = (arg1: string) => {}
const action2 = (arg1: string, arg2: {a: string, b: number}) => {}
const actions = [action1, action2]
handleActions(actions)
... elsewhere ...
const handleActions = (actions: WhatTypeIsThis[]) => {
const [action1, action2] = actions;
action1(/** infer string */)
action2(/** infer string and object */)
}
如何定义 WhatTypeIsThis
类型,以便在 handleActions
中推断操作参数?
是否可以将其定义为 actions
可以是具有不同参数列表的任意数量的函数?
是否可以使用泛型?
我的解决方案:
我标记了已接受的答案,因为它是我解决方案的灵感来源。
// get the types of the actions, defined in outer scope
type GET = typeof api.get;
type CREATE = typeof api.create;
...
// in controller
handleActions([api.getSomething, api.create])
...
// in service handler
const handleActions = (actions: [GET, CREATE]) => {
const [action1, action2] = actions;
// now we have all input / output type hints
}
这种方法让我可以将我的逻辑与 http 服务器、auth 以及我没有编写的所有其他内容隔离开来,这样我就可以安心地测试我的服务处理程序中的复杂性。
Is it possible to define it in such a way that actions can be any number of functions with varying argument lists?
对于动态列表,您需要运行时检查。我不认为你可以在不标记它们的情况下对这些函数进行运行时检查(我尝试在 length
上进行,因为这两个函数的长度不同,但它没有用,而且它真的没有用即使它有 — (arg1: string) => void
和 (arg1: number) => void
是具有相同 length
) 的不同函数。
通过品牌和运行时检查,有可能:
- 为函数定义品牌类型
- 创建函数
- 将动作列表定义为函数类型的联合数组
- 在该品牌上有
handleActions
个分店
像这样:
type Action1 = (
(arg1: string) => void
) & {
__action__: "action1";
};
type Action2 = (
(arg1: string, arg2: {a: string, b: number}) => void
) & {
__action__: "action2";
};
const action1: Action1 = Object.assign(
(arg1: string) => {},
{__action__: "action1"} as const
);
const action2: Action2 = Object.assign(
(arg1: string, arg2: {a: string, b: number}) => {},
{__action__: "action2"} as const
);
const actions = [action1, action2];
type ActionsList = (Action1 | Action2)[];
const handleActions = (actions: ActionsList) => {
const [action1, action2] = actions;
if (action1.__action__ === "action1") {
action1("x"); // <==== infers `(arg: string) => void` here
}
};
handleActions(actions);
在您添加答案顶部引用的文本之前,只读 tuple type 是可能的。我将其保留在答案中以防它对其他人有用,即使它不适用于您的情况。
这是它的样子:
type ActionsList = readonly [
(arg1: string) => void,
(arg1: string, arg2: { a: string; b: number; }) => void
];
要设为只读,您需要 as const
on actions
:
const actions = [action1, action2] as const;
// ^^^^^^^^^
元组是一种"...数组类型,它确切地知道它包含多少元素,以及它在特定位置确切地包含哪些类型。"(来自link以上)
鉴于以下情况
const action1 = (arg1: string) => {}
const action2 = (arg1: string, arg2: {a: string, b: number}) => {}
const actions = [action1, action2]
handleActions(actions)
... elsewhere ...
const handleActions = (actions: WhatTypeIsThis[]) => {
const [action1, action2] = actions;
action1(/** infer string */)
action2(/** infer string and object */)
}
如何定义 WhatTypeIsThis
类型,以便在 handleActions
中推断操作参数?
是否可以将其定义为 actions
可以是具有不同参数列表的任意数量的函数?
是否可以使用泛型?
我的解决方案:
我标记了已接受的答案,因为它是我解决方案的灵感来源。
// get the types of the actions, defined in outer scope
type GET = typeof api.get;
type CREATE = typeof api.create;
...
// in controller
handleActions([api.getSomething, api.create])
...
// in service handler
const handleActions = (actions: [GET, CREATE]) => {
const [action1, action2] = actions;
// now we have all input / output type hints
}
这种方法让我可以将我的逻辑与 http 服务器、auth 以及我没有编写的所有其他内容隔离开来,这样我就可以安心地测试我的服务处理程序中的复杂性。
Is it possible to define it in such a way that actions can be any number of functions with varying argument lists?
对于动态列表,您需要运行时检查。我不认为你可以在不标记它们的情况下对这些函数进行运行时检查(我尝试在 length
上进行,因为这两个函数的长度不同,但它没有用,而且它真的没有用即使它有 — (arg1: string) => void
和 (arg1: number) => void
是具有相同 length
) 的不同函数。
通过品牌和运行时检查,有可能:
- 为函数定义品牌类型
- 创建函数
- 将动作列表定义为函数类型的联合数组
- 在该品牌上有
handleActions
个分店
像这样:
type Action1 = (
(arg1: string) => void
) & {
__action__: "action1";
};
type Action2 = (
(arg1: string, arg2: {a: string, b: number}) => void
) & {
__action__: "action2";
};
const action1: Action1 = Object.assign(
(arg1: string) => {},
{__action__: "action1"} as const
);
const action2: Action2 = Object.assign(
(arg1: string, arg2: {a: string, b: number}) => {},
{__action__: "action2"} as const
);
const actions = [action1, action2];
type ActionsList = (Action1 | Action2)[];
const handleActions = (actions: ActionsList) => {
const [action1, action2] = actions;
if (action1.__action__ === "action1") {
action1("x"); // <==== infers `(arg: string) => void` here
}
};
handleActions(actions);
在您添加答案顶部引用的文本之前,只读 tuple type 是可能的。我将其保留在答案中以防它对其他人有用,即使它不适用于您的情况。
这是它的样子:
type ActionsList = readonly [
(arg1: string) => void,
(arg1: string, arg2: { a: string; b: number; }) => void
];
要设为只读,您需要 as const
on actions
:
const actions = [action1, action2] as const;
// ^^^^^^^^^
元组是一种"...数组类型,它确切地知道它包含多少元素,以及它在特定位置确切地包含哪些类型。"(来自link以上)