2017-11-08 6 views
2

이유 반응 바인딩을 정의 할 때 여러 유형을 허용하는 바인딩을 어떻게 결정할 수 있는지 알고 싶습니다. 예를 들어, string, number, array(string) 또는 array(number)을 받아 들여야하는 인수 ~value이 있습니다. 지금은 option('a)을 사용하고 있지만 형식을 명시 적으로 정의하는 것을 선호하므로이 방법이 가장 깨끗하다고 ​​생각하지 않습니다. 어떻게 할 수 있습니까? 나는 bs.unwrap을 보았습니다. 그러나 함수 구문에 외부 구문을 결합하는 방법을 잘 모르겠습니다.reason-react를 사용하여 함수 시그니처에서 여러 유형을 허용하는 바인딩을 정의하는 방법은 무엇입니까?

module Select = { 
    [@bs.module "material-ui/Select"] external reactClass : ReasonReact.reactClass = "default"; 
    let make = 
     (
     ... 
     ~menuProps: option(Js.t({..}))=?, 
     ~value: option('a), /* Should be type to string, number, Array of string and Array of number */ 
     ~style: option(ReactDOMRe.style)=?, 
     ... 
     children 
    ) => 
    ReasonReact.wrapJsForReason(
     ~reactClass, 
     ~props= 
     Js.Nullable.(
      { 
      ... 
      "value": from_opt(value), 
      "style": from_opt(style)    
      } 
     ), 
     children 
    ); 
}; 

이유는 숫자 형식이 정의되지 않았기 때문에 제 바인딩 또한 부동 소수점과 정수를 숫자로 매핑해야합니까?

+0

둘 다'float'과'int'는 js'number'로 표현됩니다. 따라서 기술적으로'float'을 사용하는 것만으로 도망 갈 수 있지만 편리 성을 위해 둘 다 가져 가고 싶을 것입니다. – glennsl

답변

2

이것은 다음을 사용하여 가능합니다 (https://github.com/astrada/reason-react-toolbox/에서 영감을 얻음).

type jsUnsafe; 

external toJsUnsafe : 'a => jsUnsafe = "%identity"; 

let unwrapValue = 
    (r: [< | `Int(int) | `IntArray(array(int)) | `String(string) | `StringArray(array(string))]) => 
    switch r { 
    | `String(s) => toJsUnsafe(s) 
    | `Int(i) => toJsUnsafe(i) 
    | `StringArray(a) => toJsUnsafe(a) 
    | `IntArray(a) => toJsUnsafe(a) 
    }; 

let optionMap = (fn, option) => 
    switch option { 
    | Some(value) => Some(fn(value)) 
    | None => None 
    }; 

module Select = { 
    [@bs.module "material-ui/Select"] external reactClass : ReasonReact.reactClass = "default"; 
    let make = 
     (
     ... 
     ~menuProps: option(Js.t({..}))=?, 
     ~value: 
      option(
      [ | `Int(int) | `IntArray(array(int)) | `String(string) | `StringArray(array(string))] 
      )=?, 
     ~style: option(ReactDOMRe.style)=?, 
     ... 
     children 
    ) => 
    ReasonReact.wrapJsForReason(
     ~reactClass, 
     ~props= 
     Js.Nullable.(
      { 
      ... 
      "value": from_opt(optionMap(unwrapValue, value)), 
      "style": from_opt(style)    
      } 
     ), 
     children 
    ); 
}; 

이것은 다음과 같은 방법으로 사용할 수 있습니다.

<Select value=(`IntArray([|10, 20|])) /> 
<Select value=(`Int(10)) /> 

나는 이유 - 반응 - 도구 상자에서 toJsUnsafe 복사, 그래서 나는 그것이 내가 찾을 때, 나는 내 대답을 업데이트하지 정확히 완전히 확실하지 않다.

unwrapValue 함수는 나열된 유형 중 하나 일 수있는 값을 취하여 jsUnsafe로 변환합니다.

unwrapValue의 유형은 나열된 변형을 허용하지만 그 중 일부를 허용합니다. (이 기능을 사용하기 전에 <입니다.)

module Value = { 
    type t; 
    external int : int => t = "%identity"; 
    external intArray : array(int) => t = "%identity"; 
    external string : string => t = "%identity"; 
    external stringArray : array(string) => t = "%identity"; 
}; 

let values : list(Value.t) = [ 
    Value.int(4), 
    Value.stringArray([|"foo", "bar"|]) 
]; 

이 솔루션은 또한 Value 모듈 내부 자체에 포함되어,이 문제는 이유-반응을 특정하지 않고 일반화 될 수 있기 때문에

let option = (value: option([ | `String(string) | `Int(int)])) => 
    Js.Nullable.from_opt(option_map(unwrapValue, value)); 
+0

' "% identity"'는 실제로 타입 캐스트입니다. 값을 변경하지 않고 주어진 형식 시그니처에 따라 전달 된 값의 유형이 변경되므로 최적화되므로 런타임 비용이 발생하지 않습니다. – glennsl

3

다만, @ InsidersByte의 대답에 추가 "%identity" 외부는 최적화 된 no-ops이므로 자바 스크립트에 비해 오버 헤드가 발생하지 않습니다.

관련 문제