typescript - TS 无法使用推断值创建联合类型
问题描述
我正在尝试简化 React 中共享减速器的类型,它目前可以工作,但我想让共享动作调度程序函数知道可以根据动作类型传递给它的类型。
您可以在此处查看代码的简单示例;(以及我尝试过的) TS Playground
function setDada(test: number): void {};
function addDada(): void {};
function setLala(arg: {lala: number, id: number, str: string}): void {};
interface SetDadaArg {
type: "SET_DADA",
arg: Parameters<typeof setDada>[0];
}
interface AddDadaArg {
type: "ADD_DADA",
arg: Parameters<typeof addDada>;
}
interface SetLaLa {
type: "SET_LALA",
arg: Parameters<typeof setLala>[0];
}
type ActionsArg = SetDadaArg | AddDadaArg | SetLaLa;
export type Actions = ActionsArg["type"];
const actions: Record<Actions, any> = {
SET_DADA: setDada,
ADD_DADA: addDada,
SET_LALA: setLala,
};
function dispatch(arg: ActionsArg) {
actions[arg.type](arg.arg);
}
// Type doesnt match, but should suggest me to use 'number' instead of 'string'
dispatch({type: "SET_DADA", arg: "asd"})
这个想法是定义一次函数(在化简器中,但为了简单起见,在示例之上),然后将参数的类型传递给动作调度程序函数{type, arg}
。
我可以Parameters<>
从接口中删除并在那里分配预期值,它会起作用(调度程序上的建议显示在接口中定义),但是这样做需要我再次键入函数参数,因此如果两者都可能会导致问题键入不同。这是对 TypeScript 的限制,还是有更好的方法来做到这一点?
解决方案
你可以做类似的事情
function setDada(test: number): void { };
function addDada(): void { };
function setLala(arg: { lala: number, id: number, str: string }): void { };
const actions = {
SET_DADA: setDada,
ADD_DADA: addDada,
SET_LALA: setLala,
};
export type Actions = keyof typeof actions;
type DispatchParameter<K extends Actions> = {
type: K,
arg: Parameters<typeof actions[K]>[0]
};
function dispatch<K extends Actions>(arg: DispatchParameter<K>) {
actions[arg.type](arg.arg as any);
}
// Error: Type 'string' is not assignable to type 'number'.ts(2322)
dispatch({ type: "SET_DADA", arg: "abc"});
// OK
dispatch({ type: "SET_DADA", arg: 1});
除了更简洁之外,这还具有可维护性和重构优势。所有类型都通过类型推断进行跟踪。添加新动作或删除动作所要做的就是从actions
对象中添加或删除属性。
这种方法的关键是允许类型推断完成它的工作。而不是指定不精确的中间类型,例如Record<Actions, any>
.
推荐阅读
- java - HttpsURLConnection.getErrorStream 的输出不如将 url 放在浏览器中
- javascript - 如何修复 SMS Retriever API
- azure - Azure AD B2C 是否可以设置密码有效期?
- multithreading - Powershell实例锁定主线程
- python - 列没有被删除
- python-3.x - 枚举打印而不使用 print inside loop
- php - TYPO3 9.5 LTS 更新功能损坏
- java - 未找到从另一个模块在 xml 中创建 bean
- kubernetes - 解析模板/deployment.yaml 时出错:json:第 1 行:无效字符“{”正在寻找对象键字符串的开头
- javascript - 如何在 fetch 中使用 javascript fetch 并填充数组,而不必因为异步调用而使用超时