Hone logo
Hone
Problems

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:

  1. TypeRegistry Class: Create a class named TypeRegistry. This class will be responsible for registering and checking types.
  2. registerType(typeName: string, typeConstructor: new (...args: any[]) => any) Method: This method should register a new type with the registry. It takes a typeName (string) and a typeConstructor (a constructor function for the type). The typeConstructor is used to create instances of the type.
  3. checkType(value: any, typeName: string): boolean Method: This method should check if a given value is of the specified typeName. It should return true if the value's constructor matches the registered type constructor for the given typeName, and false otherwise.
  4. Error Handling: If a type is requested for checking that hasn't been registered, the checkType method should return false.

Key Requirements:

  • The TypeRegistry should maintain a mapping between type names and their corresponding constructor functions.
  • The checkType method 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.
  • checkType should return true only if the value's constructor matches the registered constructor for the specified type name.
  • checkType should return false if 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 checkType should return false for them.)
  • What happens if the typeConstructor is not a constructor function? (The system should still function correctly, returning false in checkType.)

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 typeName must be a string.
  • The typeConstructor must be a function that can be called with new.
  • The TypeRegistry should be implemented as a class.
  • The checkType method should not throw errors. It should always return a boolean.
  • The solution should be written in TypeScript.

Notes

  • Consider using a Map or a plain JavaScript object to store the type name to constructor mapping within the TypeRegistry.
  • The checkType method should use value.constructor to 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.
Loading editor...
typescript