Type-Safe Form Library in TypeScript
Building robust and maintainable forms is a common task in web development. This challenge asks you to implement a simplified, type-safe form library in TypeScript. This library will allow developers to define forms with specific field types and validations, ensuring type safety and reducing runtime errors related to form data.
Problem Description
You are tasked with creating a basic form library that allows defining forms with typed fields and simple validation. The library should provide a way to:
- Define a Form: A form is a collection of fields.
- Define a Field: A field has a name, a type (string, number, boolean), and an optional validation function.
- Create a Form Instance: An instance of the form should hold the current values of the fields.
- Update Field Values: Provide a method to update the value of a specific field in the form instance.
- Validate the Form: Provide a method to validate the form based on the defined validation functions. This method should return a boolean indicating whether the form is valid.
Key Requirements:
- Type Safety: The library should be fully type-safe. Field values should match the declared type.
- Validation: Validation functions should be able to receive the field value and return a boolean indicating validity.
- Immutability: Updating a field should return a new form instance, not modify the existing one.
- Clear API: The library should have a clear and easy-to-use API.
Expected Behavior:
- When creating a form instance, all fields should be initialized to their default values (e.g., empty string for string fields, 0 for number fields, false for boolean fields).
- Updating a field with a value of the wrong type should result in a TypeScript error during compilation.
- The
validatemethod should returntrueif all fields are valid according to their validation functions, andfalseotherwise.
Edge Cases to Consider:
- Fields with no validation function should always be considered valid.
- Validation functions can return
trueorfalse. - Handle cases where a field is not present in the form definition. (Consider this an invalid state and return
falseduring validation).
Examples
Example 1:
Input:
Form Definition:
const myFormDefinition = {
name: { type: 'string', validation: (value: string) => value.length > 2 },
age: { type: 'number', validation: (value: number) => value >= 0 },
isActive: { type: 'boolean' }
};
Form Instance Creation:
const myForm = new Form(myFormDefinition);
Output:
{ name: '', age: 0, isActive: false }
Explanation:
The form is initialized with empty string for 'name', 0 for 'age', and false for 'isActive'.
Example 2:
Input:
Form Instance:
const myForm = new Form({
name: { type: 'string', validation: (value: string) => value.length > 2 },
age: { type: 'number', validation: (value: number) => value >= 0 },
isActive: { type: 'boolean' }
});
Field Update:
myForm.update('name', 'John');
Output:
{ name: 'John', age: 0, isActive: false }
Explanation:
The 'name' field is updated to 'John', while other fields remain unchanged.
Example 3:
Input:
Form Instance:
const myForm = new Form({
name: { type: 'string', validation: (value: string) => value.length > 2 },
age: { type: 'number', validation: (value: number) => value >= 0 },
isActive: { type: 'boolean' }
});
Validation:
myForm.validate();
Output:
false
Explanation:
The form is invalid because 'name' is an empty string, which fails the validation (length > 2).
Constraints
- The library should be implemented using TypeScript.
- The form definition should be a plain JavaScript object.
- Validation functions should accept a single argument (the field value) and return a boolean.
- The library should be relatively simple and focused on the core requirements. No need for complex UI integration or advanced validation features.
- The
updatemethod should return a new form instance.
Notes
- Consider using generics to enforce type safety.
- Think about how to represent the form definition in a way that is both flexible and type-safe.
- The validation functions are the responsibility of the user, so you don't need to provide any built-in validation rules.
- Focus on creating a clean and well-documented API.
- Start with a basic implementation and gradually add features as needed. A working, albeit simple, solution is preferable to an overly complex one.