4

I'm trying to add types to an existing React component which can render down to either an input or a textarea based on the optional textArea prop. I tried to create a discriminated union to properly account for the differing passthrough props, but TypeScript does not seem to handle a missing discriminant the same as an undefined discriminant. This is the only case I've seen where TypeScript distinguishes missing vs undefined.

Is there a way to get discrimination to work for a missing property?

This answer mentions that a discriminant must be non-optional, but that doesn't seem to be documented as far as I can tell, so I'm unsure if this is a TS bug or not.

Minimal repro:

interface NumProps {
  isString?: false
  onChange: (value: number) => void
}

interface StringProps {
  isString: true,
  onChange: (value: string) => void
}

type Props = NumProps | StringProps

const props: Props = {
  // Error: Parameter 'value' implicitly has an 'any' type.
  // Expected: 'value' is inferred as 'number'.
  onChange: value => {},
}

const propsUndefined: Props = {
  isString: undefined,
  // OK: 'value' is inferred as 'number'. 
  onChange: value => {},
}

Summary of the goal:

type InlineInputProps = { textArea?: false } & React.InputHTMLAttributes<HTMLInputElement>
type TextareaProps = { textArea: true } & React.TextareaHTMLAttributes<HTMLTextAreaElement>
type InputProps = InlineInputProps | TextareaProps
Matt Tingen
  • 118
  • 7
  • 1
    It seems that `onChange: value => {}` is not able to contextually type `value` but the type narrowing does work. It will raise an error for any annotation other than `(value: number) => {}`. – Aaron Beall May 28 '19 at 15:22
  • 4
    So `undefined` became a valid discriminant via [this pull request](https://github.com/microsoft/TypeScript/pull/27695) and made it into the [TypeScript 3.2 release](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#non-unit-types-as-union-discriminants). Of course your issue isn't that it's not acting as a discriminant, but that the contextual typing of `onChange()`'s argument seems not to be happening early enough. Not sure if there is an issue about this already, but it might be worth filing one if not. – jcalz May 28 '19 at 15:32
  • 1
    Thanks! I did not see any existing issues covering this so I created [#31618](https://github.com/microsoft/TypeScript/issues/31618) – Matt Tingen May 28 '19 at 17:14

0 Answers0