ReScript in Korean

객체

원문

리스크립트의 객체는 레코드와 비슷합니다. 하지만,

  • 타입 선언이 필요없습니다.
  • 레코드와 다르게 구조적(structural)이고 더 폴리몰픽합니다.
  • 객체가 JS로부터 전달된 것이 아니면 변경할 수 없습니다.
  • 패턴매칭을 지원하지 않습니다.

물론 리스크립트 레코드가 자바스크립트 객체로 깔끔하게 컴파일되긴 하지만, 자바스크립트 객체를 흉내내거나 바인딩할 때에는 리스크립트의 객체가 더 나은 선택일 수 있습니다.

타입 선언

레코드와는 다르게 선택적입니다. 객체의 타입은 값으로부터 추론됩니다. 그래서 타입 선언을 굳이 적을 필요가 없습니다. 그렇다 하더라도 타입 선언 문법을 보여드리자면 이렇습니다.

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

필드 이름이 따옴표로 감싸져 있는 점을 제외하면 레코드 타입의 문법과 똑같아 보입니다.

만들기

새로운 객체를 만드려면 이렇게 씁니다.

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

참고: 위에서 언급했다시피 레코드와 다르게 여기서 me"age", "name" 필드가 있는 타입 선언을 찾아서 비교하려 하지 않습니다. 오히려 me{"age": int, "name": string}로 추론됩니다. 이 점은 편리하긴 하지만 아래와 같은 의도치 않은 코드가 오류 없이 동작한다는 것을 의미합니다.

type person = {
"age": int
}
let me = {
"age": "hello!" // age가 문자열임에도 에러가 나지 않습니다.
}

이는 타입 검사기가 meperson과 매칭하려 시도하지 않기 때문입니다. 만약 어떤 객체가 기존에 선언된 객체 타입과 정확히 일치하기를 원한다면 아래와 같이 어노테이션을 주면 됩니다.

let me: person = {
"age": "hello!"
}

이러면 타입 시스템은 에러를 내줍니다.

접근

let age = me["age"]
var age = me['age'];

변경

객체가 자바스크립트 바인딩으로부터 온 것이 아니라면 수정은 되지 않습니다. 만약 수정이 되는 상황이라면 =를 쓰면 됩니다.

type student = {
@bs.set "age": int,
@bs.set "name": string,
}
@bs.module("MyJSFile") external student1: student = "student1"
student1["name"] = "Mary"

객체가 타입 선언을 필요로 하지 않는데다 리스크립트가 알아서 어떤 타입으로든 추론을 해주기 때문에, 자바스크립트 API 바인딩이 필요하다면 매우 쉽고 빠르게 만들 수 있습니다. (물론 안전하지는 않습니다)

아래 코드가 JS로 변환된 것을 보세요.

// document의 타입을 구체적으로 명시하지 않고 아무 타입 'a라고 했습니다.
@bs.val external document: 'a = "document"
// 메서드 호출
document["addEventListener"]("mouseup", _event => {
Js.log("clicked!")
})
// 프로퍼티 읽기
let loc = document["location"]
// 프로퍼티 쓰기
document["location"]["href"] = "rescript-lang.org"
document.addEventListener('mouseup', function(_event) {
console.log('clicked!');
});
var loc = document.location;
document.location.href = 'rescript-lang.org';

여기서 사용된 기법은 external 문서에도 설명이 있습니다. 이 기법이 매우 훌륭한 이유는 사용하고자 하는 JS 라이브러리의 바인딩이 있든 없든 전혀 신경쓰지 않고 일단 리스크립트 코드를 작성할 수 있기 때문입니다.