简体   繁体   中英

Typescript discriminated unions: Property does not exist on type

I'm going to use Discriminated Union type for Reducer Action.

But when I use it the compiler says the payload does not contain the property.

The code looks like


interface AuthenticatedUserState {
    user?: any
    isAdmin?: boolean
    isRegistered?: boolean
    err?: any
    isError?: boolean
    isSignedOut?: boolean
    authorizationData?: any
}

const INITIAL_STATE: AuthenticatedUserState = {
    user: null,
    isError: false,
    err: null,
    isSignedOut: false
}

interface AUTHENTICATED_USER_ACTION {
    type: 'authentication/AUTHENTICATED_USER'
    payload: {
        authenticatedUser: any
        isAdmin: boolean
    }
}

interface REGISTER_USER_ACTION {
    type: 'authentication/REGISTER_USER'
    payload: {
        isRegistered: boolean
        err: any
    }
}

const AUTHENTICATED_USER = 'authentication/AUTHENTICATED_USER'
const REGISTER_USER = 'authentication/REGISTER_USER'

type ACTION = AUTHENTICATED_USER_ACTION | REGISTER_USER_ACTION

const authenticatedUserReducer = (
    state: AuthenticatedUserState = INITIAL_STATE,
    action: ACTION
): AuthenticatedUserState => {
    const { type, payload } = action
    switch (type) {
        case AUTHENTICATED_USER:
            return {
                ...state,
                user: payload.authenticatedUser,
                isAdmin: payload.isAdmin
            }
        case REGISTER_USER:
            return {
                ...state,
                isRegistered: payload.isRegistered,
                err: payload.err
            }
        default:
            return state
    }
}

Then, the error is

Property 'err' does not exist on type '{ authenticatedUser: any; isAdmin: boolean; } | { isRegistered: boolean; err: any; }'.
  Property 'err' does not exist on type '{ authenticatedUser: any; isAdmin: boolean; }'.

You can fix the error by upgrading your TypeScript version. See playground with v4.9.4: Playground

It appears that you might be using a typescript version < 4.6.

With TS < 4.6, when you destructure a value with a discriminated-union type:

const { type, payload } = action

you are creating two new variables that have no connection with each other, nor the item from which they were destructured. The compiler is unable to narrow payload or action by means of checking type .

This behaviour changes in typescript > 4.6 , so upgrading your typescript version should be considered.

Otherwise, in a pre-TS4.6 world, don't destructure items from your discriminated union for the purpose of type-narrowing/control-flow.

switch (action.type) {
    case AUTHENTICATED_USER:
        return {
            ...state,
            user: action.payload.authenticatedUser,
            isAdmin: action.payload.isAdmin
        }
    // ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM