打字稿

时间:2018-02-05 19:15:05

标签: javascript typescript

在Typescript中建议Object.freeze还是有其他方法可以确保对象保持不变?

由于const仅保护实例,而不保护属性,因此这显然不是我正在寻找的答案。

4 个答案:

答案 0 :(得分:10)

  

还有其他方法可以确保对象保持不变吗?

这取决于您想要的保险水平。

如果您想确保没有消费者,无论是TypeScript还是JavaScript代码,都可以在运行时修改对象属性,Object.freeze就是这样做的。

如果编译时检查已足够,例如当所有使用者代码都保证仅限TypeScript并进行类型检查时,您可以使用ReadOnly generic type,它采用对象类型并生成所有properties readonly。事实上,Object.freeze()library type definitions中声明为返回ReadOnly - 其参数的修改类型:

freeze<T>(o: T): Readonly<T>;

对于seal,无法在类型系统中表示密封对象,Object.seal()declared to return the same type it receives

seal<T>(o: T): T;

Object.seal()是唯一的出路。

答案 1 :(得分:1)

最简单的解决方案:as const

这代表了在所有级别的对象或数组中的不变性的严重冻结。

const a = {
    b: 1,
    c: {d: 'e'},
    f: ['g', 'h'],
} as const

这些都不允许覆盖

a = 'not'
a.b = 'going'
a.c.d = 'to'
a.f[1] = 'change'

All result in error "TS2540: Cannot assign to '<name>' because it is a read-only property."

注意:自定义对象可能不是完全不变的,具体取决于您的实现。

奖金:如果用作枚举替换,则可以添加此行

type a = typeof a[keyof typeof a]

带有Immutable<>的不可变参数

此操作与as const相同,以深度冻结参数

// Add this and make it reuseable
type Immutable<T> = {
    readonly [K in keyof T]: Immutable<T[K]>
}

<>中定义类型,即Immutable<MyType>

_method = (a: Immutable<{b:{c:{d:[string]}}}>) => {
    // This will complain
    a.b.c.d[0] = ""
}

Official Docs

答案 2 :(得分:0)

如果需要运行时检查和编译时检查,

export const frozen:Readonly<{a:number}> = Object.freeze({a:1});

但是,以下内容已经给我带来TypeError:无法分配为只读属性

export const frozen = Object.freeze({a:1});

答案 3 :(得分:0)

在对象和函数上递归添加只读类型的Object.freeze():

export const deepFreeze = <T>(source: T, freezeParent = true): DRo<T> => {
  if (freezeParent) Object.freeze(source)

  Object.getOwnPropertyNames(source).forEach(function(prop) {
    if (
      Object.prototype.hasOwnProperty.call(source as any, prop) &&
      (source as any)[prop] !== null &&
      (typeof (source as any)[prop] === 'object' || typeof (source as any)[prop] === 'function')
    ) {
      if (Object.isFrozen((source as any)[prop])) {
        deepFreeze((source as any)[prop], false)
      } else {
        deepFreeze((source as any)[prop], true)
      }
    }
  })

  return source as DRo<T>
}

type DRo<T> = T extends (infer R)[] ? DRoArr<R> : T extends Function ? T : T extends object ? DRoObj<T> : T

interface DRoArr<T> extends ReadonlyArray<DRo<T>> {}

type DRoObj<T> = {
  readonly [P in keyof T]: DRo<T[P]>
}

Object.freeze包含Seal。