Subscribe on changes!

Optional strict mode for readonly and shallowReadonly

avatar
Aug 5th 2023

What problem does this feature solve?

The addition of strict mode to the readonly/shallowReadonly functions would bring significant benefits to developers by enhancing the reactivity system and improving debugging capabilities. Enabling strict mode on readonly variables would result in an error being thrown whenever an attempt to mutate them is made. This added safety measure ensures that all intents of mutations are explicitly tracked, making it easier to identify potential issues early in the development process.

In large projects with numerous components and complex data structures, it becomes crucial to maintain data integrity. Strict mode aids developers in confidently managing readonly variables, reducing the risk of unintentional mutations and maintaining the consistency of data across the application.

What does the proposed API look like?

const state = readonly({ count: 0 }, {strict: true}); // Enabling strict mode

export interface StrictMode {
  strict: boolean
}

export function readonly<T extends object>(
  target: T,
  strictMode?: StrictMode
): DeepReadonly<UnwrapNestedRefs<T>> {
  return createReactiveObject(
    target,
    true,
    readonlyHandlers(strictMode),
    readonlyCollectionHandlers,
    readonlyMap
  )
}

export const readonlyHandlers = (
  strictMode?: StrictMode
): ProxyHandler<object> => ({
  get: readonlyGet,
  set(target: object, key: string | symbol) {
    const setReadonlyErrorMessage = `Set operation on key "${String(
      key
    )}" failed: target is readonly.`
    if (strictMode?.strict) {
      throw new Error(setReadonlyErrorMessage, target)
    }
    if (__DEV__) {
      warn(setReadonlyErrorMessage, target)
    }
    return true
  },
  deleteProperty(target: object, key: string | symbol) {
    const deleteReadonlyErrorMessage = `Delete operation on key "${String(
      key
    )}" failed: target is readonly.`
    if (strictMode?.strict) {
      throw new Error(deleteReadonlyErrorMessage, target)
    }
    if (__DEV__) {
      warn(deleteReadonlyErrorMessage, target)
    }
    return true
  }
})