ReScript in Korean

레코드

원문

레코드(Record)는 자바스크립트 객체(Object)와 유사합니다. 다만,

  • 기본적으로 불변입니다.
  • 고정된 필드를 가지고 있습니다. (확장 불가)

타입 선언

레코드는 반드시 타입 선언을 해야합니다.

type person = {
age: int,
name: string
}

생성

person 레코드 생성 (위에 선언)

let me = {
age: 5,
name: "Big ReScript"
}

새 레코드 값을 생성할 때 리스크립트는 값의 형태가 맞는 레코드 타입 선언을 찾으려합니다. 그래서 meperson 타입으로 추론됩니다.

참고: 타입 선언이 다른 파일이나 모듈에 있는 경우 어떤 파일이나 모듈인지 명시적으로 기재해야합니다.

/* 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는 매개변수 entityage 필드와 가장 가까운 레코드 타입인 monster 타입이어야한다고 추론할 것입니다. 그래서 다음 코드의 마지막 줄이 실패합니다.

let kraken = {age: 9999, hasTentacles: true}
let me = {age: 5, name: "Baby ReScript"}
getAge(kraken)
getAge(me) /* 타입 오류! */

타입 시스템은 meperson 이고, getAgemonster 타입으로만 작동한다고 할 것입니다. 이러한 기능이 필요하다면 리스크립트 객체(object) 를 사용해보세요.

디자인 결정

동적 언어를 주로 다루셨던 분들이라면 위에서 언급된 제약을 신경쓰는게 왜 좋은지 의아할 겁니다. 레코드를 객체보다 먼저 고려하라고 하는데, 레코드는 명시적으로 타입도 써줘야 하고 모든 필드가 정확히 일치해야 함수에 전달할 수 있는 등 다루기가 더 불편하니까요.

  1. 사실은 대부분의 앱에서 데이터의 형태는 고정되어 있으며 그렇지 않은 경우 잠재적으로 배리언트 + 레코드의 조합으로 더 잘 표현 될 수 있습니다.
  2. 레코드 타입은 단일 명시적 정의(우리는 이것을 명목적 타이핑이라 부릅니다)를 통해 해소됩니다. 레코드 타입의 타입 오류 메시지가 튜플 같은 구조적 타이핑의 오류메시지보다 더 낫습니다. 이건 리팩토링을 유용하게 합니다; 레코드 타입의 필드를 변경하는 것은 자연스럽게 컴파일러에게 다른 곳에서 사용되는 레코드들에게도 같은 레코드라는 것을 알려줄 수 있습니다. 반면, 구조적 타이핑에서는 어떤 필드를 바꿨을 때, 선언이 잘못된건지 사용처가 잘못된건지 컴파일러가 추론할 방법이 없습니다.