readonly

    当然,你也可以在 interfacetype 里使用 readonly

    1. type Foo = {
    2. readonly bar: number;
    3. readonly bas: number;
    4. };
    5. // 初始化
    6. const foo: Foo = { bar: 123, bas: 456 };
    7. // 不能被改变
    8. foo.bar = 456; // Error: foo.bar 为仅读属性

    你也能指定一个类的属性为只读,然后在声明时或者构造函数中初始化它们,如下所示:

    1. class Foo {
    2. readonly bar = 1; // OK
    3. readonly baz: string;
    4. constructor() {
    5. this.baz = 'hello'; // OK
    6. }
    7. }

    这有一个 Readonly 的映射类型,它接收一个泛型 T,用来把它的所有属性标记为只读类型:

    1. type Foo = {
    2. bar: number;
    3. bas: number;
    4. };
    5. const foo: Foo = { bar: 123, bas: 456 };
    6. const fooReadonly: FooReadonly = { bar: 123, bas: 456 };
    7. foo.bar = 456; // ok
    8. fooReadonly.bar = 456; // Error: bar 属性只读

    ReactJS 是一个喜欢用不变数据的库,你可以标记你的 PropsState 为不可变数据:

    1. export class Something extends React.Component<{ foo: number }, { baz: number }> {
    2. someMethod() {
    3. this.props.foo = 123; // Error: props 是不可变的
    4. this.state.baz = 456; // Error: 你应该使用 this.setState()
    5. }
    6. }

    你甚至可以把索引签名标记为只读:

    1. interface Foo {
    2. readonly [x: number]: number;
    3. }
    4. // 使用
    5. const foo: Foo = { 0: 123, 2: 345 };
    6. console.log(foo[0]); // ok(读取)
    7. foo[0] = 456; // Error: 属性只读

    如果你想以不变的方式使用原生 JavaScript 数组,可以使用 TypeScript 提供的 ReadonlyArray<T> 接口:

    1. let foo: ReadonlyArray<number> = [1, 2, 3];
    2. console.log(foo[0]); // ok
    3. foo.push(4); // Error: ReadonlyArray 上不存在 `push`,因为他会改变数组
    4. foo = foo.concat(4); // ok, 创建了一个复制

    在一些情况下,编译器能把一些特定的属性推断为 readonly,例如在一个 class 中,如果你有一个只含有 getter 但是没有 的属性,他能被推断为只读:

    const

    • 用于变量;
    • 用于属性;

    1. const foo = 123; // 变量
    2. let bar: {
    3. readonly bar: number; // 属性
    4. };

    简单的例子 2:

    1. const foo: {
    2. readonly bar: number;
    3. } = {
    4. bar: 123
    5. };
    6. function iMutateFoo(foo: { bar: number }) {
    7. foo.bar = 456;
    8. }
    9. iMutateFoo(foo);
    10. console.log(foo.bar); // 456

    readonly 能确保“我”不能修改属性,但是当你把这个属性交给其他并没有这种保证的使用者(允许出于类型兼容性的原因),他们能改变它。当然,如果 iMutateFoo 明确的表示,他们的参数不可修改,那么编译器会发出错误警告:

    1. interface Foo {
    2. readonly bar: number;
    3. }
    4. let foo: Foo = {
    5. bar: 123
    6. };
    7. function iTakeFoo(foo: Foo) {
    8. foo.bar = 456; // Error: bar 属性只读
    9. }