Hone logo
Hone
Problems

Type Compatibility Checker in TypeScript

This challenge focuses on building functions that determine type compatibility in TypeScript. Type compatibility is a crucial aspect of TypeScript's static typing system, ensuring that values of one type can be safely used where another type is expected. Your task is to implement several functions that check for compatibility between different types, covering basic primitives, arrays, and objects.

Problem Description

You are tasked with creating a suite of functions that determine if one TypeScript type is compatible with another. Compatibility, in this context, means that a value of the first type can be safely assigned to a variable or used as an argument of a function expecting the second type. The functions should handle various scenarios, including primitive types, arrays, and objects with optional properties.

Key Requirements:

  • isPrimitiveCompatible(type1: Type, type2: Type): boolean: Checks if two primitive types (string, number, boolean, symbol, null, undefined) are compatible. type2 is considered the "expected" type.
  • isArrayCompatible(type1: Type, type2: Type): boolean: Checks if type1 (an array type) is compatible with type2 (also an array type). Compatibility requires that the element types of both arrays are compatible.
  • isObjectCompatible(type1: Type, type2: Type): boolean: Checks if type1 (an object type) is compatible with type2 (also an object type). Compatibility requires that all properties of type1 are either present in type2 with compatible types, or are optional properties in type2 with compatible types. If a property exists in type2 but not in type1, it's considered compatible.

Expected Behavior:

  • The functions should return true if the types are compatible and false otherwise.
  • The functions should handle null and undefined appropriately. null and undefined are compatible with any type.
  • The functions should correctly handle optional properties in objects.
  • The functions should be robust and handle unexpected input gracefully (though error handling beyond returning false is not required).

Edge Cases to Consider:

  • Empty arrays.
  • Objects with overlapping properties but different types.
  • Objects with optional properties.
  • Nested arrays and objects (consider limiting the depth of checking for simplicity).
  • null and undefined compatibility.
  • Union types (not required for this challenge, but good to keep in mind).

Examples

Example 1:

Input: isPrimitiveCompatible(string, number)
Output: false
Explanation: A string cannot be safely used where a number is expected.

Example 2:

Input: isArrayCompatible([number, string], [number])
Output: true
Explanation: An array of numbers and strings is compatible with an array of numbers because all numbers are also numbers.

Example 3:

Input: isObjectCompatible({ name: string, age?: number }, { name: string, age: number })
Output: false
Explanation: The first object has an optional 'age' property, while the second object requires it.  The types are not compatible.

Example 4:

Input: isObjectCompatible({ name: string }, { name: string, age: number })
Output: true
Explanation: The first object has only 'name', which is present in the second object with a compatible type.

Example 5:

Input: isPrimitiveCompatible(null, number)
Output: true
Explanation: null is compatible with any primitive type.

Constraints

  • Type Representation: For simplicity, assume Type is represented as a string. Examples: "string", "number", "boolean", "[number, string]" (for an array of numbers and strings), "{ name: string, age?: number }".
  • Object Property Representation: Object properties in the string representation will always be in the format propertyName: type. Optional properties will have a ? after the type.
  • Array Representation: Arrays will be represented as [type1, type2, ...].
  • Depth Limit: Do not implement recursive type checking for nested objects or arrays beyond a depth of 1. Focus on direct property/element type compatibility.
  • Performance: The solution should be reasonably efficient for the given constraints. Optimization is not the primary focus.

Notes

  • You'll need to parse the string representations of the types to extract the relevant information (primitive types, array element types, object property names and types).
  • Consider using regular expressions or string manipulation techniques to parse the type strings.
  • Focus on clarity and correctness over extreme optimization.
  • This challenge is designed to test your understanding of TypeScript's type system and your ability to implement type checking logic.
  • Remember that this is a simplified model of TypeScript's type compatibility rules. The actual TypeScript compiler uses a much more sophisticated algorithm.
Loading editor...
typescript