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.