Typescript JSX : Understanding Ant Design ProForm syntax

I’m trying to use Ant Design Pro Form following the documentation here : https://procomponents.ant.design/en-US/components/modal-form/

However, I keep getting syntax errors when trying to reproduce their example. What causes problem is this particular syntax :

<DrawerForm<{
   name: string;
   company: string;
}>
  title="..."
  ...
>

I first thought it was a custom syntax specific to Ant Design Pro until I realised it was probably Typescript JSX. However I’m totally unable to find a such syntax in the react docs (nor typescript docs).

I understand that DrawerForm<{name: string; company: string;}> is probablu a sort of template-type, and the {name: string; company: string;} is a data-structure that is supposed to represent the form model, but nothing is cleary explained. Can this be ommited ? What’s the point of this here (this structure doesn’t even match the form fields).

Otherwise, I was struggling with this example code from this page (https://procomponents.ant.design/en-US/components/form) :

// Set overall default values
<ProForm initialValues={obj} />

// Set the individual control's
<ProForm
 onValuesChange={(changeValues) => console.log(changeValues)}
>
  <ProFormText initialValue="prop"/>
</ProForm>.

// Interdependent component linkage
<ProForm
  <ProForm.Item noStyle shouldUpdate>
    {(form) => {
      return (
        <ProFormSelect
          options={[
            {
              value: "chapter",
              label: "Effective when stamped",
            },
          ]}
          width="md"
          name="useMode"
          label={`with${form.getFieldValue("name")}contract agreement effective mode`}
        />
      );
    }}
  </ProForm.Item>.
</ProForm>;


// Using custom components
<ProForm
  <ProForm.Item name="switch" label="Switch" valuePropName="checked">
    <Switch />
  </ProForm.Item
</ProForm

which seems erratic, tags are unclosed. Can you please confirm it is not just me who misses something ?

Answer

This is just a simple generic type. You can write a generic function

declare function reverseArray<T>(array: T[]): T[]

And then use it by adding type in angled brackets after the function name

const array: number[] = [1, 2, 3]
const reversed = reverseArray<number>(array) 

So why wouldn’t you create a generic react component

const ArrayView = <T extends any>({
  array,
  renderItem,
}: {
  array: T[],
  renderItem: (item: T) => ReactNode,
}) => ({
  <div>
    {array.map(item => renderItem(item))}
  </div>
})

And then use it by adding type in angled brackets after the function (= component) name

const array: number[] = [1, 2, 3]

<ArrayView<number>
  array={array}
  renderItem={(item) => <span>{item + 1}</span>}
/>

Except in your case the type argument is not number but {name: string, company: string}.

Of course both in normal function and react component examples you could omit the <number> part and let typescript infer types by itself, but the point remains, this is normal generic function syntax, just looking a bit weird in TSX. Also note that in the second example if you define the component with an arrow function, you must add this extends any thing because if you just write <T> typescript will think it is an opening TSX tag and confuse itself.

Actually even if the component is generic 99.99% of cases typescript is able to correctly infer everything from some prop types, that’s probably why you’ve never seen such syntax before. But sometimes you have to use it, if inference doesn’t work by itself.

And AFAIK this syntax is relatively new, so you may need to update your compiler or something for it to work. Or avoid it altogether, because you can actually make TS infer everything by specifying this type somewhere else, for example

<DrawerForm
  onFinish={async (values: {name: string, company: string}) => {
    // ...
  }}
  // ...
/>

Speaking about unclosed tags, it’s probably just a bunch of typos. If you check out the chinese version of this page, you’ll see

<ProForm>
  <Form.Item name="switch" label="Switch" valuePropName="checked">
    <Switch />
  </Form.Item>
</ProForm>

Which probably doesn’t pose any questions