Hone logo
Hone
Problems

Exhaustive Property Check in TypeScript

Ensuring that all properties of an object are present and of the correct type is crucial for maintaining code reliability and preventing runtime errors. This challenge asks you to implement a function that performs an exhaustive check against a predefined type definition, reporting any missing or incorrectly typed properties. This is particularly useful when dealing with complex data structures or APIs where strict validation is required.

Problem Description

You are tasked with creating a TypeScript function called exhaustiveCheck that takes two arguments:

  1. obj: An object of type T.
  2. typeDefinition: A TypeScript type definition T.

The function should iterate through all properties defined in typeDefinition and verify that:

  • The property exists on the obj.
  • The property's type matches the type defined in typeDefinition.

If any property is missing or has an incorrect type, the function should throw an error with a descriptive message indicating the missing or mismatched property. If all properties are present and of the correct type, the function should return undefined (or any other suitable indicator of success, but undefined is preferred for clarity).

Key Requirements:

  • The function must work with any TypeScript type definition.
  • The function must provide clear and informative error messages.
  • The function should be robust and handle various data types correctly.
  • The function should not modify the input object.

Expected Behavior:

The function should throw an error if any property is missing or has an incorrect type. It should not throw an error if all properties are present and of the correct type.

Edge Cases to Consider:

  • Objects with optional properties. The check should not throw an error if an optional property is missing.
  • Nested objects. The check should recursively validate nested objects.
  • Union types. The check should ensure the property's type is one of the union types.
  • Literal types. The check should ensure the property's value matches the literal type.
  • Readonly properties. The check should still validate these properties.

Examples

Example 1:

Input:
obj = { name: "John", age: 30 };
typeDefinition = { name: string; age: number; city?: string };

Output:
Error: Property 'city' is missing from object.

Example 2:

Input:
obj = { name: "John", age: "30", city: "New York" };
typeDefinition = { name: string; age: number; city?: string };

Output:
Error: Property 'age' has incorrect type. Expected number, got string.

Example 3:

Input:
obj = { name: "John", age: 30, city: "New York" };
typeDefinition = { name: string; age: number; city?: string };

Output:
undefined

Example 4 (Nested Object):

Input:
obj = { name: "John", address: { street: "123 Main St", city: "Anytown" } };
typeDefinition = { name: string; address: { street: string; city: string } };

Output:
undefined

Example 5 (Union Type):

Input:
obj = { status: "active" };
typeDefinition = { status: "active" | "inactive" };

Output:
undefined

Constraints

  • The input object obj can be of any shape defined by the typeDefinition.
  • The typeDefinition will always be a valid TypeScript type definition.
  • The function should be performant enough to handle reasonably sized objects (up to 100 properties). While performance is not the primary focus, avoid excessively complex or inefficient algorithms.
  • The function must be written in TypeScript.

Notes

  • Consider using TypeScript's reflection capabilities (e.g., typeof, in) to inspect the object's properties and types.
  • You may need to use type guards to perform type checking.
  • Think about how to handle optional properties gracefully.
  • Recursive validation is essential for nested objects.
  • The goal is to create a robust and reliable exhaustive check function that can be used to validate objects against TypeScript type definitions. Focus on correctness and clarity over extreme optimization.
Loading editor...
typescript