typescript - 类型 SomeType[number] 不能分配给 SomeType[number] ...嗯?
问题描述
我正在构建一个函数,它将接受一个简单的配置并返回一组完全类型化的 Redux 'actionCreators'。
该函数正在运行,当我使用返回的 actionCreators 时,我得到了正确的类型检查和自动完成。然而,Typescript 对其中一个细节不满意,我正在努力找出原因。
请注意 - 这是一项正在进行的工作,因此您可能会看到一些可以清理的外围事物,但我的问题实际上只是关于 Typescript 正在捕获的错误。
首先,我要设置几个类型——这些只是定义了将提供给 actionCreators 工厂的 TypeConfig 的类型。
interface GenericPayloads {
[key: number]: any;
}
enum GenericEnum {};
type Enum = typeof GenericEnum;
interface GenericTypeConfig {
payloads: GenericPayloads;
actionTypes: Enum;
}
然后是一个通用接口,它创建一个接口,其中包含 actionCreators 需要键入的 ActionTypes 和 Payload 类型:
interface Config<ActionTypes extends Enum, Payloads extends GenericPayloads> {
payloads: Payloads;
actionTypes: ActionTypes;
};
最后是一个通用接口,该接口将通过 Config 接口传递给通用函数(我将很快介绍)以创建一个接口,该接口表示参数中预期的配置类型:
interface ConfigAsParams<Config extends GenericTypeConfig> {
actionTypes: Config['actionTypes'];
}
然后使用工厂,我简单地定义动作类型和有效载荷如下(这些只是一些随机动作类型的例子):
enum actionTypes {
'DO_ACTION',
'DO_ANOTHER_ACTION',
'DO_FINAL_ACTION'
};
interface Payloads {
[actionTypes.DO_ACTION]: {value: string};
[actionTypes.DO_ANOTHER_ACTION]: {complete: boolean};
[actionTypes.DO_FINAL_ACTION]: undefined;
};
type MyTypeConfig = TypeConfig<typeof actionTypes, Payloads>;
几个快速的辅助函数:
const getKeys = Object.keys as <T extends Enum>(obj: T) => Array<keyof T>;
const getNumericEnumValue = <T extends Enum>(obj: T, key: keyof T): {string: false} | {string:true,value: number} => {
if (!isNaN(Number(key))) return {
string: false
};
const value = obj[key];
return {
string: true,
value: value as unknown as number
}
}
最后是函数:
function actionFactory<Config extends GenericTypeConfig>(config: ValuesConfig<Config>) {
const createActions = () => {
type ActionCreators = {
[P in keyof Config['payloads']]: (payload: Config['payloads'][P]) => {type: Config['actionTypes'][P], payload: typeof payload};
}
const actionCreators: Partial<ActionCreators> = {};
for (const key of getKeys(config.actionTypes)) {
const enumIdx = getNumericEnumValue(config.actionTypes, key);
if (!enumIdx.string) continue;
const keyAsString = key as string;
const actionCreator: ActionCreators[number] = ((payload) => ({type: keyAsString, payload}));
actionCreators[enumIdx.value] = actionCreator; // Typescript complains here
};
return actionCreators as ActionCreators;
}
return createActions;
}
此功能按预期执行,例如我可以按如下方式使用它:
const test = actionFactory<MyTypeConfig>({actionTypes});
const actionCreators = test();
const action = actionCreators ? actionCreators[actionTypes.DO_ACTION]({value: 'hello'}) : null;
我得到完全自动完成,如果我尝试传递无效的有效负载,Typescript 会抱怨,这是我想要的,并返回正确的操作。但我只是不明白为什么我会出错。
如果我按上述方式编写函数,则会出现此错误:
Type '(payload: Config["payloads"][number]) => { type: Config["actionTypes"][number]; payload: Config["payloads"][number]; }' is not assignable to type 'ActionCreators[number]'.ts(2322)
但更令人困惑的是,如果我专门创建以下类型
type ActionCreator = ActionCreators[number];
然后将其分配给 actionCreator...
const actionCreator: ActionCreator = ((payload) => ({type: keyAsString, payload}));
我收到以下错误:
Type 'ActionCreator' is not assignable to type 'ActionCreators[number]'.ts(2322)
一定是我需要在某个地方采取额外的步骤来向 Typescript 保证某些东西,但我对泛型相当陌生,所以我很难看到它。
希望有人能指出我正确的方向
解决方案
啊,我解决了。
我试图为函数分配一种类型......
ActionCreators[number]
...到具有...类型的 actionCreators 对象
Partial<ActionCreators>.
为了解决这个问题,我将类型定义如下:
const actionCreators: Partial<ActionCreators> = {};
type ActionCreator = (typeof actionCreators)[number];
然后在将函数分配给对象时:
const actionCreator: ActionCreator = ((payload) => ({type: keyAsString, payload}));
actionCreators[enumIdx.value] = actionCreator;
打字稿不再抱怨,并且 actionCreators 完全按预期输入 :)
工厂返回的 actionCreators 现在得到保证,并且不可能未定义,因此我可以按如下方式使用工厂:
const test = actionFactory<MyTypeConfig>({actionTypes});
const actionCreators = test();
const action = actionCreators[actionTypes.DO_ACTION]({value: 'hello'});
推荐阅读
- r - R中的交互式地图向下钻取能力
- python - 使用 networkx 为每个句子创建一个图
- angular - Angular MonoRepo Nx - 在应用程序中使用库
- graph - Gremlin - 按成本排序最短加权路径输出
- amazon-web-services - AWS s3 访问因所有权而被拒绝?
- java - 如何在 WKT 几何中绘制带孔的多边形
- javascript - 如果另一个用户添加了 React Node.js 内容,如何刷新标题
- python - 在 Python 中构建时间非均匀马尔可夫链
- apache-spark - 为什么我们在切换到 EMRFS 一致视图后会看到 parquet 写入错误?
- tensorflow - 如何在语义分割中删除特定的标记像素