Daniel Aviv
Daniel Aviv

Reputation: 159

Optional and required fields based on type parameters

I'm trying to make payload a required field only if T is defined:

export interface Action<T = any> {
  readonly type: string;
  readonly payload?: T;
}


// payload is a required field
const actionWithPayload: Action<string> = { action: 'action_name', payload: 'action payload'};

// payload is an optional field
const actionWithoutPayload: Action = { action: 'action_name' }

Upvotes: 1

Views: 321

Answers (1)

There are several options to achieve desired behavior. Here you have two of them

1) Union type


    interface Action1<T> {
        readonly type: string;
        readonly payload: T;
    }

    interface Action2 {
        readonly type: string;
    }

    type Action<T = never> = Action1<T> | Action2

    // payload is a required field
    const actionWithPayload: Action1<string> = { type: 'action_name', payload: 'action payload' }; // ok
    const actionWithPayload2: Action1<string> = { type: 'action_name' }; // error


    const actionWithoutPayload: Action = { type: 'action_name' } // ok
    const actionWithoutPayload2: Action = { type: 'action_name', payload: 1 } // error

2) Conditional type

    type IsAny<T> = 0 extends (1 & T) ? true : false;

    type Action<T = any> = IsAny<T> extends true ? {
        readonly type: string;
    } : {
        readonly type: string;
        readonly payload: T;
    }


    // payload is a required field
    const actionWithPayload: Action<string> = { type: 'action_name', payload: 'action payload' }; // ok
    const actionWithPayload2: Action<any> = { type: 'action_name', payload: 'action payload' }; // error


    // payload is an optional field
    const actionWithoutPayload: Action = { type: 'action_name' } // ok
    const actionWithoutPayload2: Action = { type: 'action_name', payload: 42 } // error

Upvotes: 1

Related Questions