Nominal Typing System in TypeScript
This challenge asks you to implement a simplified nominal typing system in TypeScript. Nominal typing, unlike structural typing, relies on explicit name matching to determine type compatibility. This means two types are considered compatible only if they have the same name, regardless of their structure. This exercise will help you understand the nuances of type systems and how TypeScript's type checking works.
Problem Description
You are tasked with creating a system that enforces nominal typing for a set of custom types. The system should allow you to define types by name and then check if a given value's type matches a specific type name. The core functionality revolves around a TypeRegistry that manages the defined types and provides a type checking mechanism.
What needs to be achieved:
TypeRegistryClass: Create a class namedTypeRegistry. This class will be responsible for registering and checking types.registerType(typeName: string, typeConstructor: new (...args: any[]) => any)Method: This method should register a new type with the registry. It takes atypeName(string) and atypeConstructor(a constructor function for the type). ThetypeConstructoris used to create instances of the type.checkType(value: any, typeName: string): booleanMethod: This method should check if a givenvalueis of the specifiedtypeName. It should returntrueif the value's constructor matches the registered type constructor for the giventypeName, andfalseotherwise.- Error Handling: If a type is requested for checking that hasn't been registered, the
checkTypemethod should returnfalse.
Key Requirements:
- The
TypeRegistryshould maintain a mapping between type names and their corresponding constructor functions. - The
checkTypemethod should accurately determine if a value's constructor matches the registered constructor for a given type name. - The system should be extensible to handle different types.
Expected Behavior:
- When a type is registered, it should be stored in the
TypeRegistry. checkTypeshould returntrueonly if the value's constructor matches the registered constructor for the specified type name.checkTypeshould returnfalseif the type name is not registered.
Edge Cases to Consider:
- What happens if the same type name is registered multiple times? (The last registration should overwrite previous ones.)
- How should the system handle primitive types (e.g., string, number, boolean)? (They should not be registered and
checkTypeshould returnfalsefor them.) - What happens if the
typeConstructoris not a constructor function? (The system should still function correctly, returningfalseincheckType.)
Examples
Example 1:
Input:
const registry = new TypeRegistry();
class MyType {}
registry.registerType("MyType", MyType);
const instance = new MyType();
Output:
registry.checkType(instance, "MyType") // true
registry.checkType(instance, "OtherType") // false
registry.checkType("hello", "MyType") // false
Explanation: MyType is registered. An instance of MyType is correctly identified as being of type MyType. A different type and a string are correctly identified as not being of type MyType.
Example 2:
Input:
const registry = new TypeRegistry();
class MyType {}
class AnotherType {}
registry.registerType("MyType", MyType);
registry.registerType("MyType", AnotherType); // Overwrites MyType
const instance = new AnotherType();
Output:
registry.checkType(instance, "MyType") // true
Explanation: Registering "MyType" twice results in AnotherType being the registered type. An instance of AnotherType is correctly identified as being of type MyType.
Example 3: (Edge Case - Unregistered Type)
Input:
const registry = new TypeRegistry();
const instance = new Date();
Output:
registry.checkType(instance, "MyType") // false
Explanation: MyType is not registered. Therefore, even though instance is a valid object, it cannot be of a type that hasn't been registered.
Constraints
- The
typeNamemust be a string. - The
typeConstructormust be a function that can be called withnew. - The
TypeRegistryshould be implemented as a class. - The
checkTypemethod should not throw errors. It should always return a boolean. - The solution should be written in TypeScript.
Notes
- Consider using a
Mapor a plain JavaScript object to store the type name to constructor mapping within theTypeRegistry. - The
checkTypemethod should usevalue.constructorto determine the type of the value. - This is a simplified nominal typing system. It does not include features like inheritance or generics.
- Focus on the core functionality of registering and checking types by name. Don't overcomplicate the solution.