define-getter.ts 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { isFunction, isUndefined } from 'lodash'
  2. /**
  3. *
  4. * @param obj Object on which to add or modify the property.
  5. * @param prop The property name
  6. * @param value The value of `obj[prop]` or a getter
  7. * @returns A restore function which can reset `obj[prop]`'s value or getter
  8. */
  9. const defineGetter = (
  10. obj: Record<string, any>,
  11. prop: string,
  12. value: any,
  13. defaultValue?: any
  14. ) => {
  15. let oldValue = defaultValue
  16. const { get, configurable } = Object.getOwnPropertyDescriptor(obj, prop) || {}
  17. if (isUndefined(defaultValue) && isUndefined(get)) {
  18. try {
  19. oldValue = obj[prop]
  20. } catch {
  21. throw new Error(
  22. `TypeError: Illegal invocation. Cannot read ${prop} of '${obj}', '${obj}' might be a prototype, please specify default value instead.`
  23. )
  24. }
  25. }
  26. const oldGetter = get ?? (() => oldValue)
  27. const getter = isFunction(value) ? value : () => value
  28. Object.defineProperty(obj, prop, {
  29. configurable: true,
  30. get: getter,
  31. })
  32. return () => {
  33. Object.defineProperty(obj, prop, {
  34. configurable,
  35. get: oldGetter,
  36. })
  37. }
  38. }
  39. export default defineGetter