Reputation: 107
type operation = 'create' | 'update' | 'delete';
type mutationKey = {
operation: operation;
id: K extends 'delete' | 'update' ? string : undefined; // want this field to be undefined if operation above is 'create'
}
// example 1
const ex1 = {
operation: "create"
}
// example 2
const ex2 = {
operation: "update",
id: "1"
}
Is there a way for me to type the id
field when I add operation: "create"
or any other operations in the object conditionally?
Upvotes: 3
Views: 72
Reputation: 10319
Use discriminated unions between all existing operations. This way it's easily extensible to add other operations.
interface CreateOperation {
operation: 'create'
}
interface UpdateOperation {
operation: 'update'
id: string
}
interface DeleteOperation {
operation: 'delete'
id: string
}
type Operation =
| CreateOperation
| UpdateOperation
| DeleteOperation
// example 1
const ex1: Operation = {
operation: 'create',
}
// example 2
const ex2: Operation = {
operation: 'update',
id: "1"
}
Upvotes: 3
Reputation: 23825
You can create a union of both cases.
type Operation = 'create' | 'update' | 'delete';
type MutationKey = {
operation: 'create';
id?: undefined;
} | {
operation: Exclude<Operation, "create">
id: string
}
Upvotes: 2
Reputation: 9300
You could use a generic type for this behavior.
type Operation = 'create' | 'update' | 'delete';
type mutationKey<O extends Operation> = {
[K in O extends 'create' ? never : 'id']: string;
} & { operation: O };
const ex1: mutationKey<'update'> = { operation: 'update', id: '1' };
const ex2: mutationKey<'create'> = { operation: 'create', id: '2' };
// ~~~~~~~~
// Type '{ operation: "create"; id: string; }' is not assignable to type 'mutationKey<"create">'.
// Object literal may only specify known properties, and 'id' does not exist in type 'mutationKey<"create">'.
Upvotes: 2