우선 모델링하고자 하는 값이 제공된 API에 존재하지 않는지 확인하세요.
setTimeout
와 같은 몇몇의 자바스크립트 값은 글로벌 영역에 존재합니다. 그리고 아래 처럼 바인딩 할 수 있습니다:
@bs.val external setTimeout: (unit => unit, int) => float = "setTimeout"@bs.val external clearTimeout: float => unit = "clearTimeout"
// Empty output
(JS.Global 모듈에서 이미 setTimeout
, clearTimeout
등을 제공하고 있습니다.)
이것은 자바스크립트의 setTimeout
함수와 이에 해당하는 clearTimeout
을 바인딩합니다. external
선언은 setTimeout
을 아래처럼 정의하고 있습니다.
unit
을 인자로 받고unit
과 integer를 반환하는 함수를 호출하세요.(자바스크립트에서는 아무것도 인자로 받지 않고 아무것도 반환하지 않습니다. 소위undefined
이라 정의합니다),- 여기서 integer 값은 해당 함수를 호출하기 전의 기간을 의미합니다
- 그리고 timeout의 고유번호인 숫자를 반환합니다. 이 값은 크기가 꽤 크기 때문에, 32 bit 정수형 보다는 float 타입으로 정했습니다.
팁과 트릭
위 내용은 이상적이지 않습니다. 어떻게 setTimeout
이 float
를 반환하고, clearTimeout
이 인자로 한개를 받아오는 지 봅시다. 여러분이 setTimeout
의 반환값인 float 값을 clearTimeout
에 전달할지는 알 수 없습니다! 모두 알듯이, 여러분 중 누군가는 Math.random()
을 이용하여 setTimeout
반환값을 무작위 숫자로 변환하여 clearTimeout
으로 전달할 수 도 있습니다.
리스크립트는 훌룡한 타입시스템을 가지고 있습니다! 위 문제를 해결하기 위해 널리 사용되는 기능인 추상 유형을 활용해 보겠습니다.
type timerId@bs.val external setTimeout: (unit => unit, int) => timerId = "setTimeout"@bs.val external clearTimeout: timerId => unit = "clearTimeout"let id = setTimeout(() => Js.log("hello"), 100)clearTimeout(id)
var id = setTimeout(function(param) {console.log('hello');}, 100);clearTimeout(id);
분명히 timeId
는 setTimeout
에 의해서만 만들어질 수 있는 타입입니다! 이제 clearTimeout
은 유효한 ID를 전달받는 것이 보장됩니다. ID값으로 숫자를 사용할지 말지는 내부 구현으로 감추어집니다.
external
은 인라인 처리되어있기 때문에, 손으로 쓴 자바스크립트 만큼 읽기 쉬운 자바스크립트 출력값을 얻을 수 있습니다
전역모듈(Global Modules)
글로벌 모듈 영역에서 값을 바인딩하고 싶다면, 아래 예시의 Math.random
처럼 bs.scope
을 bs.val
external에 붙이세요:
@bs.scope("Math") @bs.val external random: unit => float = "random"let someNumber = random()
var someNumber = Math.random();
bs.scope
에 튜플을 전달하여 임의로 깊은 객체를 바인딩할 수 있습니다:
@bs.val @bs.scope(("window", "location", "ancestorOrigins"))external length: int = "length"
// Empty output
위 예시는 window.location.ancestorOrigins.length
을 바인딩합니다.
특별한 전역값(Special Global Values)
__filename
, __DEV__
와 같은 전역변수는 항상 존재하진 않습니다. 심지어 이러한 전역변수들은 option
으로 모델링할 수 없습니다. 리스크립트에서 이런 전역변수를 참조하는 것 만으로도 브라우저 환경에서는 Uncaught ReferenceError: __filename is not defined
오류를 발생시키는 JS 코드가 생성됩니다.
이러한 전역변수의 문제들을 해결하기 위해 리스크립트는 특별한 문법을 제공합니다: %external(a_single_identifier)
.
switch %external(__DEV__) {| Some(_) => Js.log("dev mode")| None => Js.log("production mode")}
var match = typeof __DEV__ === 'undefined' ? undefined : __DEV__;if (match !== undefined) {console.log('dev mode');} else {console.log('production mode');}
첫번째 줄의 typeof
체크는 자바스크립트의 ReferenceError를 발생시키지 않습니다.
다른 예제
switch %external(__filename) {| Some(f) => Js.log(f)| None => Js.log("non-node environment")};
var match = typeof __filename === 'undefined' ? undefined : __filename;if (match !== undefined) {console.log(match);} else {console.log('non-node environment');}