Contract Types System in TypeScript
This challenge asks you to implement a simplified contract types system in TypeScript. Contract types are a powerful tool for defining the expected shape of data passed between functions or components, enhancing type safety and improving code maintainability. By creating a basic system, you'll gain a deeper understanding of TypeScript's type system and how it can be leveraged for more robust code.
Problem Description
You are tasked with creating a Contract class and a helper function validate that enforces contract types. The Contract class should allow you to define a set of key-value pairs, where each key represents a property name and each value represents the expected type for that property. The validate function should take an object and a Contract instance as input and return true if the object conforms to the contract (i.e., all required properties exist and have the correct types), and false otherwise.
Key Requirements:
ContractClass:- Should accept a type definition object (e.g.,
{ name: string, age: number }) during instantiation. - Should store the type definition internally.
- Should accept a type definition object (e.g.,
validateFunction:- Should take an object and a
Contractinstance as arguments. - Should iterate through the contract's type definition.
- For each property in the contract:
- Check if the property exists in the input object.
- If the property exists, check if its type matches the type defined in the contract using TypeScript's type guards.
- Should return
trueonly if all properties in the contract are present and of the correct type. Otherwise, returnfalse.
- Should take an object and a
- Type Guards: Utilize TypeScript's type guards (e.g.,
typeof,Array.isArray) to perform type checking.
Expected Behavior:
The validate function should accurately determine whether an object conforms to a given contract. It should handle cases where properties are missing or have incorrect types.
Edge Cases to Consider:
- Missing Properties: The object should fail validation if a property defined in the contract is missing.
- Incorrect Types: The object should fail validation if a property has a type that does not match the contract's definition.
- Null/Undefined Values: Consider how you want to handle
nullorundefinedvalues. For this challenge, treat them as type mismatches unless the contract explicitly allows them (e.g.,age?: number). - Optional Properties: The contract should support optional properties (e.g.,
age?: number). If a property is optional and missing, validation should still pass. - Arrays and Objects: The contract should be able to handle arrays and nested objects as types.
Examples
Example 1:
Input:
contract = new Contract({ name: string, age: number });
object = { name: "Alice", age: 30 };
Output: true
Explanation: The object has both 'name' (string) and 'age' (number) properties, matching the contract.
Example 2:
Input:
contract = new Contract({ name: string, age: number });
object = { name: "Bob" };
Output: false
Explanation: The object is missing the 'age' property, which is required by the contract.
Example 3:
Input:
contract = new Contract({ name: string, age?: number });
object = { name: "Charlie" };
Output: true
Explanation: The object has the required 'name' property (string) and the optional 'age' property is missing, which is acceptable.
Example 4:
Input:
contract = new Contract({ data: Array<string> });
object = { data: ["a", "b", "c"] };
Output: true
Explanation: The object has a 'data' property which is an array of strings, matching the contract.
Constraints
- The
Contractclass should be implemented using a class. - The
validatefunction should be a standalone function. - The contract type definitions should be plain JavaScript objects.
- The solution should be written in TypeScript.
- Performance is not a primary concern for this challenge; focus on correctness and clarity.
Notes
- Consider using TypeScript's conditional types to improve type safety within the
validatefunction. - Think about how to handle more complex type definitions (e.g., unions, intersections) if you want to extend the system further.
- This is a simplified contract system. Real-world contract systems often involve more sophisticated features like custom validation rules and error reporting.
- Focus on the core functionality of validating object properties against a defined type contract.