angular - ngrx reducer Egenskap eksisterer ikke på typen


Jeg bruker TypeScript 2.7.1 og ngrx. Mine Actions ser slik ut:

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;

min Reducer ser slik ut:

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;

Men jeg får følgende TypeScript-feil:

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; }'.

Den eneste måten jeg har funnet for å fikse dette er å eksportere en handling med et nyttelast av typen any. Hvordan kan jeg korrekt fikse dette problemet for å beholde mine typeangivelser?

Svar #1

For å bruke diskriminerte unionstyper og deres switch-typevaktadferd, må typen til type være en streng-litteral type (i praksis en strengt type som kun kan ha en enkelt verdi). Ditt type-felt er string selv om du tilordner en konstant til det. Dette skjer fordi TypeScript antar at du vil endre feltet, så det typer det som string. Hvis du markerer det som readonly og fjerner den eksplisitte string-typen, vil feltet bli typet med typen til konstanten (som er en streng-litteral type), og din switch vil korrekt typekontrollere:

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 }) { }

Eksempelkode for lekeplass

Svar #2

Lagt til det eksisterende svaret til Titian, for min del oppstår feilen hvis type-definisjonen er en streng som blir satt sammen (dette er oppførselen til min IDE-innstilling kalt hard wrap for automatisk å bryte hvis linjen er for lang). Du må sørge for at type er en konkret enkel const-streng.

Fungerer ikke

export const GET_SYSTEM_CLOSING_REPORT_OF_PROJECT_MANAGER = '[MonthClosingReportActions] Get System Closing Reports of' +
    ' project manager';
export class GetSystemClosingReportOfProjectManagerAction implements Action {
    readonly type = GET_SYSTEM_CLOSING_REPORT_OF_PROJECT_MANAGER;
    constructor(public payload: string) {}
}

Arbeidende

export const GET_SYSTEM_CLOSING_REPORT_OF_PROJECT_MANAGER = '[MonthClosingReportActions] Get System Closing Reports of project manager';
export class GetSystemClosingReportOfProjectManagerAction implements Action {
    readonly type = GET_SYSTEM_CLOSING_REPORT_OF_PROJECT_MANAGER;
    constructor(public payload: string) {}
}

Relaterte artikler