TypeScript: как привести общий объект? - PullRequest
0 голосов
/ 05 января 2019

У меня есть следующие интерфейсы:

interface AppState {
  readonly grid : IGridSettings;
  readonly selected : ISelectedSettings;
}

interface IGridSettings {
  readonly extents : number;
  readonly isXY : boolean;
  readonly isXZ : boolean;
  readonly isYZ : boolean;
  readonly spacing : number;
}

interface ISelectedSettings {
  readonly bodyColor : number;
  readonly colorGlow : number;
  readonly lineColor : number;
  readonly selection : number[] | undefined;
}

interface Action<T = any> {
  type: T
}

interface SetPropertyValueAction<KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]> extends Action {
  type : string;
  payload : {
    property : [KAction, KActionProp];
    value : IUserActions[KAction][KActionProp];
  };
}

В конце концов мой редукторный редуктор вызывается при вызове функции setPropertyValue:

const setPropertyValue = <KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]>( property : [KAction, KActionProp], value : AppState[KAction][KActionProp] ) : SetPropertyValueAction<KAction, KActionProp> => ( {
  type: 'SET_PROPERTY_VALUE',
  payload: {
    property,
    value,
  }
} );

function myReducer( state : AppState = INITIAL_STATE, a : Action ) : AppState {
  switch( a.type ) {
    case 'SET_PROPERTY_VALUE': {
      const action = a as SetPropertyValueAction; //  <- error here
      return createNewState( state, action.payload.property, action.payload.value );
    }
  }
  return states;
}

Проблема, с которой я столкнулся, заключается в том, что я не знаю, как исправить приведение из Action в SetPropertyValueAction. TypeScript говорит мне, что ошибка:

Generic type 'SetPropertyValueAction<KAction, KActionProp>' requires 2 type argument(s).

Я попытался изменить строку кода с ошибкой следующим образом:

const action = a as SetPropertyValueAction<KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]>;

... но это дает мне две ошибки: «Не удается найти имя KAction и KActionProp»

Как я могу привести объект Action к универсальному SetPropertyValueAction ??

Это дополнительный вопрос к моему другому вопросу, на который уже дан ответ: Как добавить безопасность типов TypeScript к моему действию приведения?

1 Ответ

0 голосов
/ 05 января 2019

Нам нужно указать параметры типа для типа. Поскольку мы на самом деле их не знаем, нам нужно что-то, совместимое с keyof T, но не является действительным ключом T. unknown не подойдет, поскольку он не удовлетворяет ограничению, мы можем использовать один тип any или never (который является подтипом любого типа)

interface AppState {
    readonly grid: IGridSettings;
    readonly selected: ISelectedSettings;
}

interface IGridSettings {
    readonly extents: number;
    readonly isXY: boolean;
    readonly isXZ: boolean;
    readonly isYZ: boolean;
    readonly spacing: number;
}

interface ISelectedSettings {
    readonly bodyColor: number;
    readonly colorGlow: number;
    readonly lineColor: number;
    readonly selection: number[] | undefined;
}

interface Action<T = any> {
    type: T
}

interface SetPropertyValueAction<KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]> extends Action {
    type: string;
    payload: {
        property: [KAction, KActionProp];
        value: AppState[KAction][KActionProp];
    };
}

const setPropertyValue = <KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]>(property: [KAction, KActionProp], value: AppState[KAction][KActionProp]): SetPropertyValueAction<KAction, KActionProp> => ({
    type: 'SET_PROPERTY_VALUE',
    payload: {
        property,
        value,
    }
});
declare const INITIAL_STATE: AppState;
// implementation if necessary     
function createNewState<KAction extends keyof AppState, KActionProp extends keyof AppState[KAction]>(state: AppState, property: [KAction, KActionProp], value: AppState[KAction][KActionProp]): AppState {
    return Object.assign({ ...state }, {
        [property[0]]: Object.assign({ ...state[property[0]] }, {
            [property[1]]: value,
        })
    });
}
function myReducer(state: AppState = INITIAL_STATE, a: Action): AppState {
    switch (a.type) {
        case 'SET_PROPERTY_VALUE': {
            const action = a as SetPropertyValueAction<never, never>; //  we don't know the actual type, never will have to do

            return createNewState(state, action.payload.property, action.payload.value);
        }
    }
    return state;
}
...