类型 SomeType[number] 不能分配给 SomeType[number] ...嗯?

Posted

技术标签:

【中文标题】类型 SomeType[number] 不能分配给 SomeType[number] ...嗯?【英文标题】:Type SomeType[number] is not assignable to SomeType[number] ... hmm? 【发布时间】:2021-08-18 15:15:26 【问题描述】:

我正在构建一个函数,它将接受一个简单的配置并返回一组完全类型化的 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 放心,但我对泛型还很陌生,所以我很难看到它。

希望有人能指出正确的方向

【问题讨论】:

看起来你可能在某种程度上重新发明了许多已经在官方 Redux 工具包中可用的东西。以防万一——你可能想看看它是否解决了你的问题,然后再深入了解它——它提供了非常强大的 TypeScript 支持。 感谢@phry 的提示,我会看看! 【参考方案1】:

啊,我解决了。

我试图为函数分配一种类型...

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;

Typescript 不再抱怨,actionCreators 完全按预期输入:)

工厂返回的 actionCreators 现在是确定的,不可能是未定义的,所以我可以按如下方式使用工厂:

const test = actionFactory<MyTypeConfig>(actionTypes);

const actionCreators = test();

const action = actionCreators[actionTypes.DO_ACTION](value: 'hello');

【讨论】:

以上是关于类型 SomeType[number] 不能分配给 SomeType[number] ...嗯?的主要内容,如果未能解决你的问题,请参考以下文章

'number'类型的参数不能分配给array.includes()中'never'类型的参数

“数字”类型的参数不能分配给“数字和字符串”类型的参数

类型 '() => number' 不可分配给类型 'number'

TypeScript中的定时器

运行单元测试时,“TS2322:类型 'Timeout' 不可分配给类型 'number'”

“字符串”类型的参数不可分配给“$string”类型的参数 | `$string.$string` | `$string.$number`'