#Type inference with discriminate union

6 messages · Page 1 of 1 (latest)

keen wadi
#

Hey, I have the following code which represents the props given to a React form component:

interface BaseValues {
  name: string;
  size: number;
}

interface ExtraValues extends BaseValues {
  username: string;
  password: string;
}

type FormProps =
  | {
      mode: "ADD";
      defaultValues: ExtraValues;
      onSubmit: (values: ExtraValues) => Promise<boolean>;
    }
  | {
      mode: "EDIT";
      defaultValues: BaseValues;
      onSubmit: (values: BaseValues) => Promise<boolean>;
    };

function Component(props: FormProps) {
  function handleSubmit(values: BaseValues | ExtraValues) {
      props.onSubmit(values);
  }
}

The idea is that this form component can be used in 2 "modes", adding or editing where adding requires 2 extra fields.
My question is: in the handleSubmit function, why is props.onSubmit() being inferred as (values: ExtraValues) => Promise<boolean> rather than ((values: ExtraValues) => Promise<boolean>) | ((values: BaseValues) => Promise<boolean>) ?
Since values is BaseValues | ExtraValues, TS is showing an error.

With an explicit check I can get around this,

if (props.mode === "ADD") {
  props.onSubmit(values as ExtraValues);
} else {
  props.onSubmit(values as BaseValues);
}

But I was hoping to type this somehow in order to avoid the extra (runtime) check. Any thoughts are greatly appreciated! 🙂

real jackal
#

hi! It's not, it's in fact ((values: ExtraValues) => Promise<boolean>) | ((values: BaseValues) => Promise<boolean>)

keen wadi
#

That's what I would have expected too, but the TS Playground is showing this though

nocturne agateBOT
#
MR#5314

Preview:```ts
interface BaseValues {
name: string
size: number
}

interface ExtraValues extends BaseValues {
username: string
password: string
}

type FormProps =
| {
mode: "ADD"
defaultValues: ExtraValues
onSubmit: (
values: ExtraValues
) => Promise<boolean>
}
| {
...```

keen wadi
#

If it would be inferred as ((values: ExtraValues) => Promise<boolean>) | ((values: BaseValues) => Promise<boolean>), would the call to props.onSubmit(values) still show an error?
I guess it still cannot determine that values is BaseValues when mode is EDIT at that point?

real jackal
#

funny thing, if you remove the argument, it shows the type differently