TypeScript:删除索引签名而不隐式出现“任何”类型错误

Posted

技术标签:

【中文标题】TypeScript:删除索引签名而不隐式出现“任何”类型错误【英文标题】:TypeScript: Removing index signature without getting implicitly has an 'any' type error 【发布时间】:2020-08-10 14:07:00 【问题描述】:

详情

我正在尝试创建一个辅助函数来将我的减速器组合成一个全局减速器,以便与 react 的 useReducer 钩子和上下文 API 一起使用。我有它的功能,但我目前对类型检查不满意。

问题

为了让它工作,我必须在 Reducers 类型中添加 [key: string]: Reducer<any>,在 GlobalState 类型中添加 [key: string]: any;。如果我删除它们,我会收到错误

元素隐含地具有“任何”类型,因为类型的表达式 'string' 不能用于索引类型 'GlobalState'。无索引 在类型上找到带有“字符串”类型参数的签名 '全球状态'。

元素隐含地具有“任何”类型,因为类型的表达式 'string' 不能用于索引类型'Reducers'。没有索引签名 在“Reducers”类型上找到了“字符串”类型的参数。

这给我留下了一个combineReducers 函数,我可以在其中将状态键命名为任何东西

一个例子

我的初始状态是这样的:page: some state, state2: some state 然后我像这样组合减速器:combineReducers( pages: pageReducer, state3: reducer2 );

我现在的状态看起来像 page: some state, state2: some state, pages: some state, state3: some state,因为“不小心”将状态键命名错误。

问题

在删除 Reducers 类型中的 [key: string]: Reducer<any> 和 GlobalState 类型中的 [key: string]: any; 时,有没有办法让它工作?

代码

types.ts

export type GlobalReducer = (state: GlobalState, action: Action) => GlobalState;
export type Reducer<State> = (state: State, action: Action) => State;

export type Reducers = 
    [key: string]: Reducer<any>;
    page: Reducer<PageState>;
    state2: Reducer<AnotherState>;
;

export type GlobalState = 
    [key: string]: any;
    page: PageState;
    state2: AnotherState;
;

export type PageState = 
    title: string;
    loading: true;
;

export type AnotherState = 
    hello: string;
;

combineReducers.ts

import _ from "lodash";

import  Action, Reducers, GlobalState, GlobalReducer  from "./types";

const combineReducers = (reducers: Reducers): GlobalReducer => 
    return (state: GlobalState, action: Action): GlobalState => 
        const reducerKeys = Object.keys(reducers);

        reducerKeys.forEach((key) => 
            const newState = reducers[key](state[key], action);
            state = _.isEqual(newState, state[key]) ? state :  ...state, [key]: newState ;
        );

        return state;
    ;
;

export  combineReducers ;

index.ts

export const globalReducer = combineReducers( page: pageReducer, state2: reducer2 );

initialState.ts

export const initialState: GlobalState = 
    page: 
        title: "Holidaze",
        loading: true
    ,
    state2: 
        hello: ""
    
;

【问题讨论】:

【参考方案1】:

Object.keys 返回一个字符串数组。你必须转换成keyof Reducers的数组。

const reducerKeys = Object.keys(reducers) as (keyof Reducers)[];

type GlobalState = 
    page: State1,
    anotherPage: AnotherState,


type GlobalReducer<State> = (state: State, action: Action) => State;
type Reducer<State> = (state: State, action: Action) => State;

type Reducers<State> =  [K in keyof State]: Reducer<State[K]> 

const combineReducers = <State>(reducers: Reducers<State>): GlobalReducer<State> => 
    return (state: State, action: Action): State => 
        const reducerKeys = Object.keys(reducers) as (keyof State)[];

        reducerKeys.forEach((key) => 
            const newState = reducers[key](state[key], action);
            state = _.isEqual(newState, state[key]) ? state :  ...state, [key]: newState ;
        );

        return state;
    ;
;

【讨论】:

这有帮助!但是我仍然收到 const newState = reducers[key](state[key], action); 行的错误。 'PageState | 类型的参数AnotherState' 不可分配给“PageState & AnotherState”类型的参数。是 state[key] 产生错误 修复它!谢谢:)

以上是关于TypeScript:删除索引签名而不隐式出现“任何”类型错误的主要内容,如果未能解决你的问题,请参考以下文章

元素隐式具有“任何”类型,因为类型“窗口”没有索引签名?

type 'typeof globalThis' 没有索引签名

TypeScript 和 Vue 类 - TS7053 索引签名

右值引用:为啥不隐式移动右值?

如何在不隐式调用“复制”的情况下初始化 CUDA 推力向量?

如何为映射类型添加索引签名?