TypeScript中“readonly”的用法

时间:2017-09-25 08:18:04

标签: typescript readonly

用法1:函数声明其参数不会被修改

这种用法很简单:作为契约,函数doSomething声明它不会改变接收的参数。

interface Counter {
  name: string
  value: number
}

function doSomething(c: Readonly<Counter>) {
  // ...
}

let c = {
  name: "abc",
  value: 123
}
doSomething(c)
// Here we are sure that 'c.name' is "abc" and 'c.value' is '123'

用法2:工厂声明其输出无法修改

使用此代码:

interface Counter {
  readonly name: string
  readonly value: number
  inc(): number
}

function counterFactory(name: string): Counter {
  let value = 0
  return {
    get name() {
      return name
    },
    get value() {
      return value
    },
    inc() {
      return ++value
    }
  }
}

我们这里有一个成员readonly value,无法直接从外部修改。但是成员inc()可以改变该值。此外,成员value被声明为readonly,但其值正在发生变化。

我想知道在成员readonly上使用value是否是一种很好的方法。语法没问题。但是这个示例在TypeScript中是否在语义上正确?那是修饰语readonly的用途吗?

2 个答案:

答案 0 :(得分:2)

属性上的readonly关键字不能确保属性值是常量。没有类似的TypeScript。我们可以确定只读属性的唯一事项是:

  1. 其价值无法从消费者方面改变→用法1。
  2. 它可以是get-only属性→用法2的推断类型。请注意,如果未定义counterFactory返回类型,则推断它与Counter接口完全相同,请参阅下面的代码中的(A)。
  3. 其值只能设置一次且仅在对象构造期间→请参阅下面的(B)。
  4. 代码示例:

    // (A) Usage 2 using type inference
    const counter = counterFactory('foo');
    type Counter = typeof counter; // Produce the exact same type as the previous `Counter` interface
    counter.value = 10; // [Ts Error] Can not assign to 'value' because it is a constant or read-only property
    
    // (B) Readonly property initialization
    // (B1) With an object literal + interface 
    const manualCounter: Counter = { name: 'bar', value: 2, inc: () => 0 };
    manualCounter.value = 3; // [Ts Error] Can not assign...
    
    // (B2) With a class
    class Foo {
      constructor(public name: string, public readonly value: number) { }
      inc() {
        return ++this.value; // [Ts Error] Can not assign...
      }
    }
    
    const foo = new Foo('bar', 3);
    foo.value = 4; // [Ts Error] Can not assign...
    
    // (C) Circumvent TypeScript
    Object.assign(foo, { value: 4 }); // → No error neither in Ts, nor at runtime
    

    它真的令人困惑,因为它几乎就像一个不变的财产!用法2和案例C证明它不是。

答案 1 :(得分:0)

造成混乱的是&#34; double&#34;使用'value&#39;在你的工厂功能。

澄清一下,用这种方式重写(请注意_value变量前面的_):

interface Counter {
    readonly name: string
    readonly value: number
    inc(): number
}

function counterFactory(name: string): Counter {
    let _value = 0
    return {
        get name() {
            return name
        },
        get value() {
            return _value
        },
        inc() {
            return ++_value
        }
    }
}
  1. _value只是一个局部var而不是你可以改变
  2. get value()实现了界面定义readonly value: numbercounter.value readonly