Typescript can't narrow function signature on sum type of component props

Advertisements

I have a component that takes two possible callbacks. The callback that should be passed depends on the other properties, if property type is passed with value A, then it should use callback A, if type is passed as B then it should use callback B. To express this dichotomy I am using a sum type for the entire props object, using the type as a tag.

I tried all kind of combinations for the tab, but I can not get TS to recognise that I’m passing the right callback.

Here is a simplification of the code:

import React from 'react'
type SessionDefinition = {name: string}
type SessionDefinitionFromDb = {name: string, id: string}

type CreateCb = (definition: SessionDefinition) => Promise<void>;
type UpdateCb = (definition: SessionDefinitionFromDb) => Promise<void>;

type Props =
  | {
      isLoading: boolean;
      onSubmit: CreateCb;
      definition: SessionDefinition;
      action: 'create';
    }
  | {
      isLoading: boolean;
      onSubmit: UpdateCb;
      definition: SessionDefinitionFromDb;
      action: 'update';
    }

export default function DefinitionForm(props: Props) {
  return <div>'Test'</div>
}
<DefinitionForm 
isLoading
onSubmit={(x:SessionDefinitionFromDb) => console.log(x)}
definition={{ id: 'test', name:'text'}}
action='update'
/

The error typescript complains about is:

Type '(x: SessionDefinitionFromDb) => void' is not assignable to type 'CreateCb | UpdateCb'.
  Type '(x: SessionDefinitionFromDb) => void' is not assignable to type 'CreateCb'.
    Types of parameters 'x' and 'definition' are incompatible.
      Property 'id' is missing in type 'SessionDefinition' but required in type 'SessionDefinitionFromDb'.

And here is a Playground example

>Solution :

The error message is confusing, but the problem seems to come from the fact that your callback returns void, and not Promise<void> as expected. So replacing the said callback with (x: SessionDefinitionFromDb) => new Promise(() => console.log(x)) seems to solve it, as Typescript isn’t complaining anymore for me.

Leave a Reply Cancel reply