[Typescript] 07. 읽기 전용
포스트
취소

[Typescript] 07. 읽기 전용

Readonly

Javascript에서 객체를 구성하는 수많은 AttributesWritable하면서 Readable하다.
따지고 보면 수정하면 안되는 Attribute마저도 수정이 가능하다.

1
2
3
4
const test = 'good';
console.log(test.length); // 4;
test.length = 777; // success
console.log(test.length); // 4;

string이나 arraylength Attribute에 직접 값을 입력하는게 가능하다.
물론 실제로 값이 변경되어 엉뚱한 값이 나오는 것은 아니지만 값을 대입 할 때 아무런 오류 없이 통과가 된다는 것 자체가 원하는 그림이 아니다. Javascript는 기본적으로 const로 정의 된 값이 아니라면 재정의가 가능하기 때문에 생기는 이슈이다.

이번엔 같은 소스코드를 Typescript에서 실행시켜보자.

1
2
3
4
const test = 'good';
console.log(test.length); // 4;
test.length = 777; // Cannot assign to 'length' because it is a read-only Attribute.(2540)
console.log(test.length);

우리가 원하는대로 length Attribute가 read-only 값으로 인식되어 수정이 불가능하다.

Typescript에는 readonly키워드가 있기 때문에 가능한 일이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
type ButtonProps = {
    title?: string,
    disabled?: boolean,
    readonly onPress?: Function,
};

const submitButtonProps: ButtonProps = {
    title: '전송',
    onPress: (): void => console.log('Submit!'),
};

submitButtonProps.onPress = () => console.log('Not Submit!'); // Cannot assign to 'onPress' because it is a read-only Attribute.(2540)
// ...

위 예제처럼 ButtonProps Type을 정의하고, submitButtonProps 객체를 ButtonProps Type으로 정의한다면 onPress Attribute에 대하여 최초로 정의한 값에서 재정의를 진행할 때 에러를 뱉는다.

주의할 점

readonly 키워드가 정의되면 모든 방식의 수정을 차단하는 것은 아니다. readonly 키워드는 대상의 재정의만을 차단하는 속성이기 때문이다.

Readonly 속성이 붙은 객체의 Attribute 수정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type ButtonProps = {
    title?: string,
    disabled?: boolean,
    readonly onPress?: Function,
    readonly children: { a: Number, b: Number },
};

const submitButtonProps: ButtonProps = {
    title: '전송',
    onPress: (): void => console.log('Submit!'),
    children: {
        a: 1,
        b: 2,
    }
};

submitButtonProps.children.a = 2;

submitButtonProps.childrenreadonly Attribute가 맞지만, submitButtonProps.children.areadonly가 아니므로 수정이 가능하다.

구조가 동일한 서로 다른 type의 재정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Person {
  name: string;
  age: number;
}
 
interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}
 
let writablePerson: Person = {
  name: "Person McPersonface",
  age: 42,
};
 
// works
let readonlyPerson: ReadonlyPerson = writablePerson;
 
console.log(readonlyPerson.age); // prints '42'
writablePerson.age++;

위 소스코드를 보면 writablePerson은 모든 Attributes의 수정이 가능한 InterfacePersonType으로 사용했다.
그런데 ReadonlyPerson이라는 type을 보면 모든 Attributereadonly로 정의 되어있다.
변수 readonlyPersonReadonlyPerson Type을 따르기 때문에 Attributes의 재정의가 원래는 불가능 해야한다. 하지만 readonlyPerson의 값을 WritablePerson Type을 베이스로 정의 된 writablePerson 변수로 정의했으니 readonlyPersonAttributes마저 수정이 가능하다.

왜냐하면 변수를 대입하는 과정에서 Type의 호환 여부를 식별할 때 readonly비교 대상에서 제외되기 때문이다.

재정의가 불가능한 Array

1
2
3
4
5
type ArrayType = readonly [number, number, number];
const arr: ArrayType = [1, 2, 3];

arr[1] = 1; // Cannot assign to '1' because it is a read-only property.
console.log(arr);

객체 뿐 아니라 배열도 readonly 속성을 통해 데이터의 재정의를 막을 수 있다.

type 정의를 하지 않는 재정의가 불가능한 Array

1
const arr = [1, 2, 3, 4, 5, 6, 7] as const;

readonly 튜플을 이용하여 배열을 정의하면 해당 배열의 type이 자동으로 readonly [1, 2, 3, 4, 5, 6, 7]이 된다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.