简体   繁体   中英

React Typescript - dynamic types

Is it possible to have dynamic type? I have a json like this

{
  "fieldName": "Some text",
  "type": String,
  "inputType": "text"
},
{
  "fieldName": "Some bool",
  "type": Boolean,
  "inputType": "checkbox
}

And based on that json I would like to render field components like this one

const Field: React.FC<FieldInterface> = ({ name, type, handler }) => {
  const [value, setValue] = useState<type>()

  const handleOnChane = (e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value)
    handler(name, e.target.value)
  }

  return (
    <div>
      <label htmlFor={name}>{name}</label>
      <input
        type={type}
        id={name}
        onChange={handleOnChane}
        value={value}
      ></input>
    </div>
  )
}
export default Field

here are my interfaces

export interface FormInterface {
  fields: FieldPropInterface[]
  submitAction: Function
}

export interface FieldPropInterface {
  name: string
  inputType: string
  type: <Here I would like to have something but don't know what>
}

export interface FieldInterface {
  name: string
  type: string
  handler: Function
}

You see, I need that type to set type of useState hook variable. Is it possible to do that?

Repo link: https://github.com/johnathan-codes/react-form-from-json

Use alternative types.

export interface FieldPropInterface {
  name: string;
  inputType: string;
  type: Boolean | String;
}

The other responses will work, but they aren't making use of the full power of typescript. What you want is to establish a relationship between the fields inputType and type such that fields with {inputType: "checkbox"} must always be boolean , {inputType: "text"} must always be string , and so on.

Here's how you would do that with a Union Type (you could also make use of a map or a conditional, but I won't get in to that).

type FieldPropInterface = {
    fieldName: string;
} & ({
    type: "string";
    inputType: "text";
} | {
    type: "boolean";
    inputType: "checkbox";
})

You need to read up a bit more onthe HTML input element and its props because you want to treat a checkbox differently than a text input. Checkboxes set their value through a boolean property called checked rather than value which is a string. There are also loads of packages on npm that can make dealing with forms a lot easier.

If you want useState to be generic then your component Field should be generic.

You've also said that your FieldInterface.handler can be any type of Function , but you need to be specific about what that function is.

{ handler: (e: ChangeEvent<HTMLInputElement>) => void; }

or maybe it can become a function of value rather than event with a different setup.

Are you sure that you know what you're doing when using the capitalized name String ? The capitalized name means that the value is the String constructor, whereas the lowercase means that the value is a string . From the docs :

Don't ever use the types Number, String, Boolean, Symbol, or Object These types refer to non-primitive boxed objects that are almost never used appropriately in JavaScript code.

If you are using this as a flag, just to say "this value is a string" or "this value is a boolean" you might consider using the literal string "string" and "boolean" rather than the object constructors, but I don't know where and how this is actually being used in your code.

You can also do something like this:

export interface FieldInterface<T> {
  name: string
  type: T
  handler: Function
}

const Field: React.FC<FieldInterface<typeof type>> = ({ name, type, handler }) => {
  const [value, setValue] = useState<type>()

  const handleOnChane = (e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value)
    handler(name, e.target.value)
  }

  return (
    <div>
      <label htmlFor={name}>{name}</label>
      <input
        type={type}
        id={name}
        onChange={handleOnChane}
        value={value}
      ></input>
    </div>
  )
}
export default Field

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM