or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

field.mdform-spy.mdform.mdhooks.mdindex.mdtypescript.md

typescript.mddocs/

0

# TypeScript Support

1

2

Utility functions and type helpers for enhanced TypeScript support with strongly typed form and field components.

3

4

## Capabilities

5

6

### withTypes Utility

7

8

Utility function that provides strongly typed Form and FormSpy components for specific form value types.

9

10

```typescript { .api }

11

/**

12

* Creates strongly typed Form and FormSpy components for specific form values

13

* @returns Object with typed Form and FormSpy components

14

*/

15

function withTypes<FormValues = Record<string, any>>(): {

16

Form: React.ComponentType<FormProps<FormValues>>;

17

FormSpy: React.ComponentType<FormSpyProps<FormValues>>;

18

};

19

```

20

21

**Usage Examples:**

22

23

```typescript

24

import { withTypes } from "react-final-form";

25

26

// Define your form values interface

27

interface UserFormValues {

28

firstName: string;

29

lastName: string;

30

email: string;

31

age: number;

32

isActive: boolean;

33

}

34

35

// Create strongly typed components

36

const { Form, FormSpy } = withTypes<UserFormValues>();

37

38

// Now Form and FormSpy are fully typed for UserFormValues

39

function TypedUserForm() {

40

const onSubmit = (values: UserFormValues) => {

41

// values is fully typed as UserFormValues

42

console.log(values.firstName); // TypeScript knows this is a string

43

console.log(values.age); // TypeScript knows this is a number

44

};

45

46

return (

47

<Form

48

onSubmit={onSubmit}

49

initialValues={{

50

firstName: "John", // Type-checked

51

lastName: "Doe", // Type-checked

52

email: "john@example.com",

53

age: 30,

54

isActive: true

55

}}

56

render={({ handleSubmit, values }) => (

57

<form onSubmit={handleSubmit}>

58

{/* values is typed as UserFormValues */}

59

<div>Name: {values.firstName} {values.lastName}</div>

60

61

<FormSpy>

62

{({ values: spyValues }) => (

63

<div>

64

{/* spyValues is also typed as UserFormValues */}

65

Email: {spyValues.email}

66

Age: {spyValues.age}

67

</div>

68

)}

69

</FormSpy>

70

71

<button type="submit">Submit</button>

72

</form>

73

)}

74

/>

75

);

76

}

77

```

78

79

### Version Information

80

81

Access to the current version of react-final-form.

82

83

```typescript { .api }

84

/**

85

* Current version of react-final-form

86

*/

87

const version: string;

88

```

89

90

**Usage Example:**

91

92

```typescript

93

import { version } from "react-final-form";

94

95

function VersionInfo() {

96

return <div>React Final Form version: {version}</div>;

97

}

98

```

99

100

### TypeScript Type Definitions

101

102

Complete type definitions for all components, hooks, and interfaces.

103

104

```typescript { .api }

105

/**

106

* Core form component type

107

*/

108

type FormComponent<FormValues = Record<string, any>> = React.ComponentType<

109

FormProps<FormValues>

110

>;

111

112

/**

113

* Core field component type

114

*/

115

type FieldComponent<

116

FieldValue = any,

117

T extends HTMLElement = HTMLElement,

118

FormValues = Record<string, any>

119

> = React.ComponentType<FieldProps<FieldValue, T, FormValues>>;

120

121

/**

122

* FormSpy component type

123

*/

124

type FormSpyComponent<FormValues = Record<string, any>> = React.ComponentType<

125

FormSpyProps<FormValues>

126

>;

127

128

/**

129

* Generic render prop function type

130

*/

131

type RenderFunction<T> = (props: T) => React.ReactNode;

132

133

/**

134

* Form render prop function type

135

*/

136

type FormRenderFunction<FormValues = Record<string, any>> = RenderFunction<

137

FormRenderProps<FormValues>

138

>;

139

140

/**

141

* Field render prop function type

142

*/

143

type FieldRenderFunction<

144

FieldValue = any,

145

T extends HTMLElement = HTMLElement,

146

FormValues = any

147

> = RenderFunction<FieldRenderProps<FieldValue, T, FormValues>>;

148

149

/**

150

* FormSpy render prop function type

151

*/

152

type FormSpyRenderFunction<FormValues = Record<string, any>> = RenderFunction<

153

FormSpyRenderProps<FormValues>

154

>;

155

```

156

157

### Advanced TypeScript Patterns

158

159

Comprehensive examples of advanced TypeScript usage with react-final-form.

160

161

**Usage Examples:**

162

163

```typescript

164

import React from "react";

165

import { Form, Field, FormSpy, withTypes } from "react-final-form";

166

167

// Complex form values interface

168

interface ComplexFormValues {

169

personalInfo: {

170

firstName: string;

171

lastName: string;

172

dateOfBirth: Date;

173

};

174

contactInfo: {

175

email: string;

176

phone?: string;

177

address: {

178

street: string;

179

city: string;

180

zipCode: string;

181

};

182

};

183

preferences: {

184

newsletter: boolean;

185

theme: "light" | "dark";

186

notifications: string[];

187

};

188

}

189

190

// Create typed components

191

const { Form: TypedForm, FormSpy: TypedFormSpy } = withTypes<ComplexFormValues>();

192

193

// Typed field component

194

function TypedField<K extends keyof ComplexFormValues>({

195

name,

196

...props

197

}: {

198

name: K;

199

} & React.InputHTMLAttributes<HTMLInputElement>) {

200

return (

201

<Field name={name as string}>

202

{({ input, meta }) => (

203

<div>

204

<input {...input} {...props} />

205

{meta.error && meta.touched && <span>{meta.error}</span>}

206

</div>

207

)}

208

</Field>

209

);

210

}

211

212

// Generic field component with type inference

213

function GenericField<T extends HTMLElement = HTMLInputElement>({

214

name,

215

component = "input" as any,

216

...props

217

}: {

218

name: string;

219

component?: keyof JSX.IntrinsicElements | React.ComponentType<any>;

220

} & React.HTMLAttributes<T>) {

221

return (

222

<Field name={name} component={component} {...props} />

223

);

224

}

225

226

// Strongly typed form validation

227

function validateComplexForm(values: Partial<ComplexFormValues>) {

228

const errors: Partial<Record<keyof ComplexFormValues, any>> = {};

229

230

if (!values.personalInfo?.firstName) {

231

errors.personalInfo = { firstName: "Required" };

232

}

233

234

if (!values.contactInfo?.email) {

235

errors.contactInfo = { email: "Required" };

236

}

237

238

return errors;

239

}

240

241

// Complete typed form

242

function ComplexTypedForm() {

243

const onSubmit = (values: ComplexFormValues) => {

244

// All properties are type-safe

245

console.log(values.personalInfo.firstName);

246

console.log(values.contactInfo.email);

247

console.log(values.preferences.theme);

248

};

249

250

return (

251

<TypedForm

252

onSubmit={onSubmit}

253

validate={validateComplexForm}

254

initialValues={{

255

personalInfo: {

256

firstName: "",

257

lastName: "",

258

dateOfBirth: new Date()

259

},

260

contactInfo: {

261

email: "",

262

address: {

263

street: "",

264

city: "",

265

zipCode: ""

266

}

267

},

268

preferences: {

269

newsletter: false,

270

theme: "light",

271

notifications: []

272

}

273

}}

274

render={({ handleSubmit, values }) => (

275

<form onSubmit={handleSubmit}>

276

<TypedField name="personalInfo" placeholder="This would need proper nested handling" />

277

278

<TypedFormSpy>

279

{({ values: formValues }) => (

280

<div>

281

Theme: {formValues.preferences?.theme}

282

Newsletter: {formValues.preferences?.newsletter ? "Yes" : "No"}

283

</div>

284

)}

285

</TypedFormSpy>

286

287

<button type="submit">Submit</button>

288

</form>

289

)}

290

/>

291

);

292

}

293

```

294

295

### Type Utilities and Helpers

296

297

Additional type utilities for working with form state and field values.

298

299

```typescript { .api }

300

/**

301

* Extract field value type from form values

302

*/

303

type FieldValueType<

304

FormValues,

305

FieldName extends keyof FormValues

306

> = FormValues[FieldName];

307

308

/**

309

* Create partial form values type for updates

310

*/

311

type PartialFormValues<FormValues> = Partial<FormValues>;

312

313

/**

314

* Form values with all fields optional (for initial values)

315

*/

316

type InitialFormValues<FormValues> = Partial<FormValues>;

317

318

/**

319

* Extract render props type for specific component

320

*/

321

type ExtractRenderProps<T> = T extends React.ComponentType<infer P>

322

? P extends { render?: (props: infer R) => any }

323

? R

324

: never

325

: never;

326

327

/**

328

* Type-safe field name extractor

329

*/

330

type FieldNames<FormValues> = keyof FormValues | string;

331

332

/**

333

* Validation error type for form values

334

*/

335

type FormErrors<FormValues> = Partial<Record<keyof FormValues, any>>;

336

337

/**

338

* Field validation function type

339

*/

340

type FieldValidationFunction<FieldValue, FormValues = any> = (

341

value: FieldValue,

342

allValues: FormValues,

343

meta?: any

344

) => any | Promise<any>;

345

346

/**

347

* Form validation function type

348

*/

349

type FormValidationFunction<FormValues> = (

350

values: FormValues

351

) => FormErrors<FormValues> | Promise<FormErrors<FormValues>>;

352

```

353

354

**Usage Examples:**

355

356

```typescript

357

// Using type utilities

358

interface UserForm {

359

name: string;

360

email: string;

361

age: number;

362

}

363

364

// Extract specific field type

365

type NameFieldType = FieldValueType<UserForm, "name">; // string

366

type AgeFieldType = FieldValueType<UserForm, "age">; // number

367

368

// Create validation functions with proper typing

369

const validateName: FieldValidationFunction<string, UserForm> = (

370

value,

371

allValues,

372

meta

373

) => {

374

if (!value) return "Name is required";

375

if (value.length < 2) return "Name must be at least 2 characters";

376

return undefined;

377

};

378

379

const validateUserForm: FormValidationFunction<UserForm> = (values) => {

380

const errors: FormErrors<UserForm> = {};

381

382

if (!values.name) errors.name = "Required";

383

if (!values.email) errors.email = "Required";

384

if (values.age < 18) errors.age = "Must be 18 or older";

385

386

return errors;

387

};

388

389

// Type-safe field names

390

const userFormFields: (keyof UserForm)[] = ["name", "email", "age"];

391

```

392

393

### Integration with External Type Systems

394

395

Examples of integrating react-final-form with popular TypeScript libraries.

396

397

**Usage Examples:**

398

399

```typescript

400

// Integration with Zod schema validation

401

import { z } from "zod";

402

403

const userSchema = z.object({

404

name: z.string().min(1, "Name is required"),

405

email: z.string().email("Invalid email"),

406

age: z.number().min(18, "Must be 18 or older")

407

});

408

409

type UserFormValues = z.infer<typeof userSchema>;

410

411

const validateWithZod = (values: UserFormValues) => {

412

try {

413

userSchema.parse(values);

414

return {};

415

} catch (error) {

416

if (error instanceof z.ZodError) {

417

return error.formErrors.fieldErrors;

418

}

419

return {};

420

}

421

};

422

423

// Integration with react-hook-form-like patterns

424

function createTypedForm<T>() {

425

return {

426

Form: withTypes<T>().Form,

427

FormSpy: withTypes<T>().FormSpy,

428

useFormState: () => useFormState<T>(),

429

useForm: () => useForm<T>()

430

};

431

}

432

433

const userFormComponents = createTypedForm<UserFormValues>();

434

```