Issue
I'm using TypeScript 2.7.1 and ngrx. My Actions look like this:
import { Action } from '@ngrx/store';
export const HEALTH_FORM_CONTENT_CHANGED = '[setupHealthForm] Content Changed';
export const HEALTH_FORM_TITLE_CHANGED = '[setupHealthForm] Title Changed';
export class SetupHealthFormContentChangedAction implements Action {
public type: string = HEALTH_FORM_CONTENT_CHANGED;
constructor(public payload: { content: string }) { }
}
export class SetupHealthFormTitleChangedAction implements Action {
public type: string = HEALTH_FORM_TITLE_CHANGED;
constructor(public payload: { title: string }) { }
}
export type Actions
=
SetupHealthFormContentChangedAction
| SetupHealthFormTitleChangedAction;
my Reducer looks like this:
import { Actions, HEALTH_FORM_TITLE_CHANGED, HEALTH_FORM_CONTENT_CHANGED } from './setup-health-form.actions';
export interface State {
title: string;
body: string;
}
const initialState: State = {
title: '',
body: ''
}
export function reducer(state: State = initialState, action: Actions): State {
switch (action.type) {
case HEALTH_FORM_TITLE_CHANGED: {
return {
...state,
...{ title: action.payload.title }
}
}
case HEALTH_FORM_CONTENT_CHANGED: {
return {
...state,
...{ body: action.payload.content }
}
}
default: {
return state;
}
}
}
export const body = (state: State) => state.body;
export const title = (state: State) => state.title;
However I get the following typescript errors:
error TS2339: Property 'title' does not exist on type '{ content: string; } | { title: string; }'.
error TS2339: Property 'content' does not exist on type '{ content: string; } | { title: string; }'.
The only way i've found to fix this is exporting an action with a payload of type any. How do I correctly fix this issue to retain my typings?
Solution
To use discriminated union types and their switch type guard behavior, the type of type has to be a string literal type (basically a string type that can only be a single value). Your type field is string even through you assign a constant to it. This happens because typescript assumes that you will want ot mutate the field so it types it as string. If you mark it as readonly and remove the explicit string type the field will be typed with the type of the constant (which is a string literal type) and your switch will correctly type check:
export class SetupHealthFormContentChangedAction {
public readonly type = HEALTH_FORM_CONTENT_CHANGED;
constructor(public payload: { content: string }) { }
}
export class SetupHealthFormTitleChangedAction implements Action {
public readonly type = HEALTH_FORM_TITLE_CHANGED
constructor(public payload: { title: string }) { }
Answered By - Titian Cernicova-Dragomir
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.