Home > Software design >  Infer a type within a type from an object
Infer a type within a type from an object

Time:08-11

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?

CodePudding user response:

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"
}

CodePudding user response:

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">'.

CodePudding user response:

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
}

Playground

  • Related