Hone logo
Hone
Problems

Variance Annotations in TypeScript: Ensuring Type Safety with Generics

Variance annotations in TypeScript allow you to precisely control how subtyping relationships are handled when working with generic types. This is crucial for maintaining type safety when dealing with collections or functions that operate on generic types, preventing unexpected errors and ensuring code correctness. This challenge will test your understanding of extends and supertype variance annotations.

Problem Description

You are tasked with creating a generic Collection class that manages a collection of elements. This class should support adding elements, retrieving elements, and ensuring type safety based on the variance of the generic type T. You need to implement variance annotations using extends and supertype to correctly handle subtyping relationships when dealing with the Collection class. Specifically, you need to ensure that if B is a subtype of A, then Collection<B> is a subtype of Collection<A>.

Key Requirements:

  • Implement a Collection class with a generic type parameter T.
  • Implement an add method to add elements of type T to the collection.
  • Implement a get method to retrieve elements from the collection.
  • Apply extends variance annotation to the generic type parameter T to ensure subtype compatibility.
  • The Collection class should be able to store and retrieve elements of the specified type.
  • The get method should return a Promise<T> to simulate asynchronous operations.

Expected Behavior:

  • Creating a Collection<string> should allow adding strings.
  • Creating a Collection<number> should allow adding numbers.
  • If string is a subtype of object, then Collection<string> should be assignable to Collection<object>.
  • The get method should return a Promise resolving to the type of element stored in the collection.

Edge Cases to Consider:

  • Empty collections.
  • Adding elements of the wrong type (should result in a TypeScript error).
  • Subtyping relationships between generic types.

Examples

Example 1:

Input:
class Animal {}
class Dog extends Animal {}

const stringCollection = new Collection<string>();
const objectCollection = new Collection<object>();

stringCollection.add("hello");
objectCollection.add({name: "test"});

// Should be valid due to variance
let collectionOfObjects: Collection<object> = stringCollection;

Output: void (no runtime output, but TypeScript should not report any errors) Explanation: string is a subtype of object, and the extends variance annotation ensures that Collection<string> is assignable to Collection<object>.

Example 2:

Input:
class Animal {}
class Dog extends Animal {}

const dogCollection = new Collection<Dog>();
const animalCollection = new Collection<Animal>();

dogCollection.add(new Dog());
animalCollection.add(new Animal());

// Should be valid due to variance
let collectionOfAnimals: Collection<Animal> = dogCollection;

Output: void (no runtime output, but TypeScript should not report any errors) Explanation: Dog is a subtype of Animal, and the extends variance annotation ensures that Collection<Dog> is assignable to Collection<Animal>.

Example 3: (Edge Case)

Input:
class Animal {}
class Dog extends Animal {}

const stringCollection = new Collection<string>();
const animalCollection = new Collection<Animal>();

// Should result in a TypeScript error:
// Type 'string' is not assignable to type 'Animal'.
// animalCollection.add("hello");

Output: TypeScript compilation error. Explanation: A string is not assignable to Animal, demonstrating the type safety enforced by the generic type parameter.

Constraints

  • The Collection class must be implemented in TypeScript.
  • The add method must accept a single argument of type T.
  • The get method must return a Promise<T>.
  • The variance annotation must be correctly applied to the generic type parameter T.
  • The code should be well-structured and readable.
  • No external libraries are allowed.

Notes

  • Consider using Promise to simulate asynchronous operations for the get method.
  • The extends variance annotation is key to achieving subtype compatibility.
  • Think carefully about how subtyping relationships between generic types should be handled.
  • Focus on ensuring type safety and preventing unexpected errors. The goal is to demonstrate a correct understanding of variance annotations.
Loading editor...
typescript