Reputation: 159
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
Reputation: 33041
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