Chronomorphic Types in TypeScript: Temporal Data Structures
Chronomorphisms, in the context of types, allow us to associate a timestamp with a value, effectively creating a "versioned" or "temporal" data structure. This challenge asks you to implement a system that allows you to track changes to a value over time, retrieving the value as it existed at a specific point in the past. This is useful for auditing, version control, and implementing features like "undo/redo" functionality.
Problem Description
You need to create a generic ChronomorphicType that can wrap any TypeScript type T. This type should allow you to store multiple versions of the value T, each associated with a timestamp (represented as a number, where higher numbers represent later times). The ChronomorphicType should provide a method to retrieve the value of the type T at a given timestamp. If no version exists at the specified timestamp, it should return undefined.
Key Requirements:
- Generic Type: The
ChronomorphicTypemust be generic, accepting any typeTas a parameter. - Timestamped Values: Store values along with their timestamps.
- Retrieval by Timestamp: Provide a method
getValueAt(timestamp: number): T | undefinedto retrieve the value at a specific timestamp. - Immutability: The internal state of the
ChronomorphicTypeshould be immutable after creation. Adding new versions should not modify existing versions. - No External Dependencies: The solution should not rely on external libraries.
Expected Behavior:
- When a new value is added, it should be stored with the current timestamp.
getValueAt()should return the value associated with the latest timestamp that is less than or equal to the provided timestamp.- If no value exists at or before the given timestamp,
getValueAt()should returnundefined. - The order of values should be maintained based on their timestamps.
Edge Cases to Consider:
- Empty
ChronomorphicType: What happens whengetValueAt()is called on an emptyChronomorphicType? - Timestamp before any stored values: What happens when
getValueAt()is called with a timestamp earlier than any stored timestamp? - Multiple values with the same timestamp: Which value should be returned? (The problem doesn't specify, so you can choose a reasonable behavior, but document your choice.)
- Large number of versions: Consider the performance implications of retrieving values from a large number of stored versions. (While optimization isn't the primary focus, be mindful of potential inefficiencies.)
Examples
Example 1:
Input:
const chronomorphicNumber = new ChronomorphicType<number>();
chronomorphicNumber.addValue(10, Date.now());
chronomorphicNumber.addValue(20, Date.now() + 1000);
chronomorphicNumber.addValue(30, Date.now() + 2000);
Output:
chronomorphicNumber.getValueAt(Date.now() + 1500); // 20
Explanation: The value 20 was added at a timestamp between Date.now() + 1000 and Date.now() + 2000, which is the latest value before Date.now() + 1500.
Example 2:
Input:
const chronomorphicString = new ChronomorphicType<string>();
chronomorphicString.addValue("hello", Date.now());
chronomorphicString.addValue("world", Date.now() + 500);
Output:
chronomorphicString.getValueAt(Date.now() - 100); // undefined
Explanation: No value exists before Date.now() - 100.
Example 3:
Input:
const chronomorphicBoolean = new ChronomorphicType<boolean>();
chronomorphicBoolean.addValue(true, Date.now());
chronomorphicBoolean.addValue(false, Date.now());
Output:
chronomorphicBoolean.getValueAt(Date.now()); // false
Explanation: When timestamps are equal, the latest added value (false) is returned. This behavior is documented in the Notes section.
Constraints
- Timestamp Type: Timestamps must be represented as numbers.
- Value Type: The value
Tcan be any valid TypeScript type. - Time Complexity: While not a primary focus, avoid excessively inefficient algorithms. A linear search through the stored versions is acceptable for this challenge.
- Memory Usage: The solution should be reasonably memory-efficient.
Notes
- You will need to create a class or a similar structure to implement the
ChronomorphicType. - Consider how you will store the timestamped values internally (e.g., an array, a map).
- When multiple values have the same timestamp, the most recently added value should be returned by
getValueAt(). This is a design choice, and you should document it. - Error handling is not required for this challenge. Assume valid input.
- Focus on clarity and correctness over extreme optimization. The goal is to demonstrate understanding of the concept and ability to implement it in TypeScript.