Readonly
Javascript
에서 객체를 구성하는 수많은 Attributes
는 Writable
하면서 Readable
하다.
따지고 보면 수정하면 안되는 Attribute
마저도 수정이 가능하다.
1
2
3
4
const test = 'good';
console.log(test.length); // 4;
test.length = 777; // success
console.log(test.length); // 4;
string
이나 array
의 length
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.children
은 readonly
Attribute가 맞지만, submitButtonProps.children.a
는 readonly
가 아니므로 수정이 가능하다.
구조가 동일한 서로 다른 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
의 수정이 가능한 Interface
인 Person
을 Type
으로 사용했다.
그런데 ReadonlyPerson
이라는 type
을 보면 모든 Attribute
가 readonly
로 정의 되어있다.
변수 readonlyPerson
은 ReadonlyPerson Type
을 따르기 때문에 Attributes
의 재정의가 원래는 불가능 해야한다. 하지만 readonlyPerson
의 값을 WritablePerson Type
을 베이스로 정의 된 writablePerson
변수로 정의했으니 readonlyPerson
의 Attributes
마저 수정이 가능하다.
왜냐하면 변수를 대입하는 과정에서 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]
이 된다.