Hone logo
Hone
Problems

Creating a Read-Only Ref in Vue with TypeScript

Vue's ref provides a reactive way to store data. However, sometimes you need to ensure a ref's value cannot be modified directly, preventing accidental or unintended changes. This challenge focuses on creating a utility function that wraps a ref and makes it effectively read-only while still maintaining reactivity.

Problem Description

You are tasked with creating a function called readonlyRef that takes a Vue ref as input and returns a new ref that behaves identically to the original but prevents direct modification of its value. The returned ref should still be reactive, meaning changes to the underlying value (e.g., through a method that modifies it) should trigger updates in the component. Direct assignment to the returned ref should be prevented, throwing an error if attempted.

Key Requirements:

  • The function must accept a Vue ref as an argument.
  • The returned value must be a Vue ref.
  • Accessing the value of the returned ref should return the same value as the original ref.
  • Direct assignment to the returned ref should throw a TypeError.
  • Changes to the underlying value of the original ref (e.g., through a method that modifies it) should still trigger reactivity and update the returned ref.

Expected Behavior:

  • readonlyRef(ref) should return a new ref object.
  • readonlyRef(ref).value should return the same value as ref.value.
  • Attempting to assign a new value to readonlyRef(ref).value should throw a TypeError with a descriptive message.
  • If the original ref is updated, the returned ref should reflect that change.

Edge Cases to Consider:

  • The input ref might already be a reactive object.
  • The input ref might be initialized with a primitive value (number, string, boolean).
  • The input ref might be initialized with an object or array.

Examples

Example 1:

Input:
const originalRef = ref(10);
readonlyRef(originalRef);
Output:
A new ref object with value 10.
Explanation:
The function creates a new ref that initially holds the same value as the original ref.

Example 2:

Input:
const originalRef = ref("Hello");
const readonlyRefInstance = readonlyRef(originalRef);

try {
  readonlyRefInstance.value = "World";
} catch (error) {
  console.error(error.message); // Expected: "Cannot directly modify a readonly ref."
}
Output:
TypeError: Cannot directly modify a readonly ref.
Explanation:
Attempting to directly assign a new value to the readonly ref throws an error.

Example 3:

Input:
const originalRef = ref([1, 2, 3]);
const readonlyRefInstance = readonlyRef(originalRef);

originalRef.value.push(4); // Modifying the underlying array

console.log(readonlyRefInstance.value); // Output: [1, 2, 3, 4]
Explanation:
Even though the readonly ref is created, modifying the underlying array through the original ref still triggers reactivity and updates the readonly ref.

Constraints

  • The solution must be written in TypeScript.
  • The solution must use Vue 3's ref API.
  • The function readonlyRef should be performant and not introduce significant overhead.
  • The error message thrown when attempting to modify the readonly ref should be clear and informative.

Notes

Consider using a proxy to intercept assignments to the ref.value property. Remember that the goal is to prevent direct assignment, not to prevent modifications to the underlying value if they are made through other means (e.g., methods that mutate the value). Focus on creating a clean and reusable utility function.

Loading editor...
typescript