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.type2is considered the "expected" type.isArrayCompatible(type1: Type, type2: Type): boolean: Checks iftype1(an array type) is compatible withtype2(also an array type). Compatibility requires that the element types of both arrays are compatible.isObjectCompatible(type1: Type, type2: Type): boolean: Checks iftype1(an object type) is compatible withtype2(also an object type). Compatibility requires that all properties oftype1are either present intype2with compatible types, or are optional properties intype2with compatible types. If a property exists intype2but not intype1, it's considered compatible.
Expected Behavior:
- The functions should return
trueif the types are compatible andfalseotherwise. - The functions should handle
nullandundefinedappropriately.nullandundefinedare 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
falseis 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).
nullandundefinedcompatibility.- 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
Typeis 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.