Material-ui: TextField TS Error with `variant` prop

Created on 14 May 2019  路  10Comments  路  Source: mui-org/material-ui


When passing a conditional statement to the variant prop of the TextField component like this:

<TextField
  variant={isLongTextQuestion ? "outlined" : "standard"}
  ...
/>

I get a typescript error saying:

Types of property 'variant' are incompatible.
      Type '"standard" | "outlined"' is not assignable to type '"outlined"'.
        Type '"standard"' is not assignable to type '"outlined"'.ts(2322)

  • [x] This is not a v0.x issue.
  • [x] I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior 馃

TextField component should allow this statement as it accepts both outlined and standard independently.

Current Behavior 馃槸

Gives typescript type error

Steps to Reproduce 馃暪


Link:

https://codesandbox.io/s/mor0mrooz9

Context 馃敠

Your Environment 馃寧

| Tech | Version |
|--------------|---------|
| Material-UI | v3.9.3 |
| React | v16.8.4 |
| Browser | |
| TypeScript | |
| etc. | |

TextField typescript

Most helpful comment

I figured out a workaround. For anyone else who sees this, try this:

interface MyTextInputProps extends BaseTextFieldProps {
  readonly foo: number;
}

const MyTextInput: FC<MyTextInputProps> = ({ foo, ...props }) => {
  const newLabel = foo.toString();

  /**
   * Hack to make 'props.variant' type safe
   *
   * See: https://github.com/mui-org/material-ui/issues/15697
   */
  const tsProps = (() => {
    let tsVariant;
    switch (variant) {
      case "outlined": {
        tsVariant = { variant: variant as "outlined" };
        break;
      }
      case "filled": {
        tsVariant = { variant: "filled" as "filled" };
        break;
      }
      case "standard":
      default: {
        tsVariant = { variant: "standard" as "standard" };
        break;
      }
    }
    const p = props;
    delete p.variant;
    return { ...p, ...tsVariant };
  })();
  return <TextInput label={newLabel} {...tsProps} />;
}

It's far from ideal though as the only purpose of this entire function is to fix the props.variant bug.

All 10 comments

Looks more like how Typescript work and not material-ui issue itself... https://github.com/Microsoft/TypeScript/issues/16870

This is a limitation in TypeScript. Basically { type: 'bird' | 'fish' } is not assignable to { type: 'bird' } | { type: 'fish' }. See microsoft/TypeScript#8289.

I don't know of any sound solution without runtime overhead. Until then maybe

function App({ isLongTextQuestion }: { isLongTextQuestion: boolean }) {
  const variantProps = isLongTextQuestion
    ? // or use const expression
      { variant: "outlined" as "outlined" }
    : { variant: "standard" as "standard" };

  const props: StandardTextFieldProps | OutlinedTextFieldProps = {
    id: "test",
    type: "text",
    value: "abc",
    rows: 3,
    multiline: isLongTextQuestion,
    ...variantProps
  };

  return <TextField {...props} />;
}

works for you?

Ah, I see. That'll work @eps1lon, thanks a lot!

I'm running into the same issue and I'm not sure how to fix it with your above workaround.

Basic example (I know the example doesn't make contextual sense but basically all I'm doing is extending the default TextInput component):

interface MyTextInputProps extends BaseTextFieldProps {
  readonly foo: number;
}
const MyTextInput: FC<MyTextInputProps> = ({ foo, ...props }) => {
  const newLabel = foo.toString();
  return <TextInput label={newLabel} {...props} />;
}

How would I fix this? Are there any plans to update MUI so that the BaseTextFieldProps work properly?

I figured out a workaround. For anyone else who sees this, try this:

interface MyTextInputProps extends BaseTextFieldProps {
  readonly foo: number;
}

const MyTextInput: FC<MyTextInputProps> = ({ foo, ...props }) => {
  const newLabel = foo.toString();

  /**
   * Hack to make 'props.variant' type safe
   *
   * See: https://github.com/mui-org/material-ui/issues/15697
   */
  const tsProps = (() => {
    let tsVariant;
    switch (variant) {
      case "outlined": {
        tsVariant = { variant: variant as "outlined" };
        break;
      }
      case "filled": {
        tsVariant = { variant: "filled" as "filled" };
        break;
      }
      case "standard":
      default: {
        tsVariant = { variant: "standard" as "standard" };
        break;
      }
    }
    const p = props;
    delete p.variant;
    return { ...p, ...tsVariant };
  })();
  return <TextInput label={newLabel} {...tsProps} />;
}

It's far from ideal though as the only purpose of this entire function is to fix the props.variant bug.

Thanks a lot @TidyIQ!

Hi guys I found this issue as well.. quite frustrating bug :-) thanks for the solution.

this must be joke, so resolution is importing this helper anywhere its needed ?

fuck dat and do this:

<TextField variant={control.textFieldVariant as any} />

I had react error when tried as any from previous answer

My way

class TextViewVariety {
    static FILLED = 'filled' as 'filled'
    static OUTLINED = 'outlined' as 'outlined'
}
...
variant={ this.props.variety as any }

It works well

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rbozan picture rbozan  路  3Comments

ghost picture ghost  路  3Comments

finaiized picture finaiized  路  3Comments

ryanflorence picture ryanflorence  路  3Comments

zabojad picture zabojad  路  3Comments