1

I have a function that accepts a parameter which is an object consisting of a field (string) and arguments (object literal).

I'd like the arguments type check to be validated dependent on what the field is. I also wish to make a definition that can be extended wherever I needed (hence the generic).

Definition:

 export interface EventDefinition<
    TField extends string,
    TArgs extends any
  > {
    field: TField
    arguments: TArgs
  }

My function:


export const myFn =  (
  params:
    | EventDefinition<
        'actionOne',
        {
          id: string
        }
      >
    | EventDefinition<
        'actionTwo',
        {
          emailAddress: string
        }
      >
) => {
  const { args, field } = params

  switch(field) {
    case 'actionOne':
      console.log(args.id)
      break;
      case 'actionTwo':
      console.log(args.emailAddress)
      break;
  }
}

While the field property validates the args do not and result in errors (for ex with args.id):

Property 'id' does not exist on type '{ id: string }'.
Property 'id' does not exist on type '{ emailAddress: string; }'.

How can I correctly define this?

1 Answer 1

3

Typescript will not guard one variable based on another, this is just not supported.

If you use the argument itself control flow analysis can determine the types appropriately

  switch(params.field) {
    case 'actionOne':
      console.log(params.arguments.id)
      break;
      case 'actionTwo':
      console.log(params.arguments.emailAddress)
      break;
  }

Playground Link

Sign up to request clarification or add additional context in comments.

2 Comments

Shoot. I saw an answer by you regarding Mapping Interface which I think should work albeit losing some flex. stackoverflow.com/questions/56949513/…
@cyberwombat you already have a discriminated union, just as I suggested in the other answer. Your only issue is that you can't type guard on separate values, you need to keep everything in one variable

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.