레코드(Record)는 자바스크립트 객체(Object)와 유사합니다. 다만,
- 기본적으로 불변입니다.
- 고정된 필드를 가지고 있습니다. (확장 불가)
타입 선언
레코드는 반드시 타입 선언을 해야합니다.
type person = {age: int,name: string}
생성
person
레코드 생성 (위에 선언)
let me = {age: 5,name: "Big ReScript"}
새 레코드 값을 생성할 때 리스크립트는 값의 형태가 맞는 레코드 타입 선언을 찾으려합니다. 그래서 me
는 person
타입으로 추론됩니다.
참고: 타입 선언이 다른 파일이나 모듈에 있는 경우 어떤 파일이나 모듈인지 명시적으로 기재해야합니다.
/* School.res */type person = {age: int, name: string}/* Example.res */let me: School.person = {age: 20, name: "Big ReScript"}/* or */let me2 = {School.age: 20, name: "Big ReScript"}
첫번째는 School.res
파일에 레코드 타입을 정의한 것이며, 두/세번째는 School.res
파일에 정의된 레코드 타입을 명시하는 방법입니다.
접근
익숙한 .(dot) 어노테이션을 사용합니다.
let name = me.name
불변 수정
...
spread 연산자를 사용해 이전 레코드로에서 새 레코드를 만들 수 있습니다. 원본 레코드는 변경되지 않습니다.
let meNextYear = {...me, age: me.age + 1}
참고: spread는 레코드 형태가 타입에 따라 고정되므로 레코드값에 새 필드를 추가할 수 없습니다.
가변 수정
레코드 필드는 선택적으로 변경 가능(mutable
)할 수 있습니다. 이렇게하면 =
연산자를 사용해 해당 필드를 효율적으로 업데이트 할 수 있습니다.
type person = {name: string,mutable age: int}let baby = {name: "Baby ReScript", age: 5}baby.age = baby.age + 1 /* `baby.age` is now 6. Happy birthday! */
타입 선언에 가변(mutable
)으로 표시되어 있지 않은 필드는 변경할 수 없습니다.
자바스크립트 결과물
리스크립트 레코드는 자바스크립트 객체로 컴파일 됩니다.
팁
레코드 타입은 필드 이름으로 찾습니다. "이 함수는 age
필드가 있는 모든 레코드 타입을 사용하고 싶습니다." 와 같은 것은 불가능합니다. 다음은 의도한대로 동작하지 않습니다:
type person = {age: int, name: string}type monster = {age: int, hasTentacles: bool}let getAge = (entity) => entity.age
getAge
는 매개변수 entity
가 age
필드와 가장 가까운 레코드 타입인 monster
타입이어야한다고 추론할 것입니다. 그래서 다음 코드의 마지막 줄이 실패합니다.
let kraken = {age: 9999, hasTentacles: true}let me = {age: 5, name: "Baby ReScript"}getAge(kraken)getAge(me) /* 타입 오류! */
타입 시스템은 me
가 person
이고, getAge
는 monster
타입으로만 작동한다고 할 것입니다. 이러한 기능이 필요하다면 리스크립트 객체(object) 를 사용해보세요.
디자인 결정
동적 언어를 주로 다루셨던 분들이라면 위에서 언급된 제약을 신경쓰는게 왜 좋은지 의아할 겁니다. 레코드를 객체보다 먼저 고려하라고 하는데, 레코드는 명시적으로 타입도 써줘야 하고 모든 필드가 정확히 일치해야 함수에 전달할 수 있는 등 다루기가 더 불편하니까요.
- 사실은 대부분의 앱에서 데이터의 형태는 고정되어 있으며 그렇지 않은 경우 잠재적으로 배리언트 + 레코드의 조합으로 더 잘 표현 될 수 있습니다.
- 레코드 타입은 단일 명시적 정의(우리는 이것을 명목적 타이핑이라 부릅니다)를 통해 해소됩니다. 레코드 타입의 타입 오류 메시지가 튜플 같은 구조적 타이핑의 오류메시지보다 더 낫습니다. 이건 리팩토링을 유용하게 합니다; 레코드 타입의 필드를 변경하는 것은 자연스럽게 컴파일러에게 다른 곳에서 사용되는 레코드들에게도 같은 레코드라는 것을 알려줄 수 있습니다. 반면, 구조적 타이핑에서는 어떤 필드를 바꿨을 때, 선언이 잘못된건지 사용처가 잘못된건지 컴파일러가 추론할 방법이 없습니다.