最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React Typescript - dynamic types - Stack Overflow

programmeradmin2浏览0评论

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 ponents 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:

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 ponents 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./johnathan-codes/react-form-from-json

Share Improve this question edited Oct 6, 2020 at 8:10 Johnathan3 asked Oct 5, 2020 at 12:10 Johnathan3Johnathan3 431 silver badge7 bronze badges 4
  • have you already taken a look at the typescript typeof operator? – A_A Commented Oct 5, 2020 at 12:14
  • 1 Consider reading typescript docs. It's kinda basics of the basics. – kind user Commented Oct 5, 2020 at 12:16
  • @A_A But that doesn't resolve a constructor like String to the type string-you're still relying on the types you supply. OP is trying to use runtime info for static typing. – Andrew Li Commented Oct 5, 2020 at 12:22
  • 1 I think what you actually want is a union type which enforces a relationship between properties inputType and type. – Linda Paiste Commented Oct 5, 2020 at 15:31
Add a ment  | 

3 Answers 3

Reset to default 3

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 on the 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 ponent 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 bee 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.

Use alternative types.

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

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
发布评论

评论列表(0)

  1. 暂无评论