Hone logo
Hone
Problems

Type System Simulator in TypeScript

This challenge asks you to build a simplified type system simulator in TypeScript. Simulating a type system is crucial for understanding how languages like TypeScript, Java, and C# enforce type safety, and it's a valuable exercise in abstracting complex concepts. Your simulator will focus on basic type checking and inference.

Problem Description

You are to implement a type system simulator that can evaluate expressions and determine their types based on a predefined set of types and operations. The simulator should be able to handle basic types (number, string, boolean), and a few common operations (addition, string concatenation, logical AND). The core of the simulator is a TypeChecker class that takes an expression and returns its inferred type.

What needs to be achieved:

  • Define a set of basic types (e.g., NumberType, StringType, BooleanType).
  • Implement a TypeChecker class with an inferType method.
  • The inferType method should take an expression (represented as a JavaScript object – see below) and return the inferred type.
  • The simulator should handle basic type checking for operations like addition and string concatenation.
  • The simulator should support basic type inference.

Key Requirements:

  • Expression Representation: Expressions will be represented as JavaScript objects with the following structure:
    • type: A string indicating the type of the expression (e.g., "literal", "binary").
    • value: (Optional) The literal value of the expression (e.g., 10, "hello", true). Only present for literal expressions.
    • operator: (Optional) The operator for binary expressions (e.g., "+", "+").
    • left: (Optional) The left-hand side expression for binary expressions.
    • right: (Optional) The right-hand side expression for binary expressions.
  • Type Definitions: Create TypeScript classes or interfaces to represent the different types (e.g., NumberType, StringType, BooleanType). These should be abstract enough to represent the core concept of a type.
  • Type Checking: The inferType method should perform type checking based on the expression's structure and the types of its operands.
  • Type Inference: The inferType method should infer the type of an expression if it's not explicitly specified.

Expected Behavior:

The inferType method should return a type object (e.g., an instance of NumberType, StringType, or BooleanType) that represents the inferred type of the expression. If the expression is invalid or the types are incompatible, the method should return null.

Edge Cases to Consider:

  • Operations on incompatible types (e.g., adding a number and a string).
  • Expressions with missing operands.
  • Literal values of different types.
  • Nested expressions.

Examples

Example 1:

Input: { type: "literal", value: 10 }
Output: { type: "NumberType" }
Explanation: A literal value of 10 is a number.

Example 2:

Input: { type: "literal", value: "hello" }
Output: { type: "StringType" }
Explanation: A literal value of "hello" is a string.

Example 3:

Input: { type: "binary", operator: "+", left: { type: "literal", value: 5 }, right: { type: "literal", value: 3 } }
Output: { type: "NumberType" }
Explanation: Adding two numbers results in a number.

Example 4:

Input: { type: "binary", operator: "+", left: { type: "literal", value: 5 }, right: { type: "literal", value: "3" } }
Output: null
Explanation: Adding a number and a string is an invalid operation.

Example 5:

Input: { type: "binary", operator: "&&", left: { type: "literal", value: true }, right: { type: "literal", value: false } }
Output: { type: "BooleanType" }
Explanation: Logical AND of two booleans results in a boolean.

Constraints

  • Expression Complexity: The expressions will be relatively simple, with a maximum nesting depth of 3.
  • Supported Operators: Only the following operators are supported: + (addition), + (string concatenation), && (logical AND).
  • Type Set: Only the following types are supported: NumberType, StringType, BooleanType.
  • Performance: The inferType method should execute in O(n) time, where n is the size of the expression tree. While optimization isn't the primary focus, avoid excessively inefficient algorithms.

Notes

  • Start by defining the Type interface/classes. This will provide a foundation for your type checking logic.
  • Consider using recursion to traverse the expression tree.
  • Think about how to handle type compatibility between different types.
  • Error handling is important. Return null when an invalid expression or type mismatch is encountered.
  • This is a simplified simulator. Real-world type systems are significantly more complex. The goal is to demonstrate the core principles of type checking and inference.
  • Focus on clarity and correctness over extreme optimization. Well-structured code is more important than micro-optimizations.
Loading editor...
typescript