문제

불행하게도 0.9.5부터 TypeScript에는 (아직) 대수 데이터 유형(공용체 유형)과 패턴 일치(구조 분해)가 없습니다.게다가 인터페이스에서는 인스턴스 오브(instanceof)도 지원하지 않습니다.최대 유형 안전성과 최소한의 상용구 코드로 이러한 언어 기능을 에뮬레이션하기 위해 어떤 패턴을 사용합니까?

도움이 되었습니까?

해결책 2

다른 팁

나는 다음과 같은 방문자와 같은 패턴을 사용했습니다. 이것 그리고 이것 (예제에서는 Choice 될 수 있다 Foo 또는 Bar):

interface Choice {
    match<T>(cases: ChoiceCases<T>): T;
}

interface ChoiceCases<T> {
    foo(foo: Foo): T;
    bar(bar: Bar): T;
}

class Foo implements Choice {

    match<T>(cases: ChoiceCases<T>): T {
        return cases.foo(this);
    }

}

class Bar implements Choice {

    match<T>(cases: ChoiceCases<T>): T {
        return cases.bar(this);
    }

}

용법:

function getName(choice: Choice): string {
    return choice.match({
        foo: foo => "Foo",
        bar: bar => "Bar",
    });
}

일치 자체는 표현력이 풍부하고 유형이 안전하지만 유형에 대해 작성해야 할 상용구가 많습니다.

예제가 수락 된 답변을 설명하는 예제 :

enum ActionType { AddItem, RemoveItem, UpdateItem }
type Action =
    {type: ActionType.AddItem, content: string} |
    {type: ActionType.RemoveItem, index: number} |
    {type: ActionType.UpdateItem, index: number, content: string}

function dispatch(action: Action) {
    switch(action.type) {
    case ActionType.AddItem:
        // now TypeScript knows that "action" has only "content" but not "index"
        console.log(action.content);
        break;
    case ActionType.RemoveItem:
        // now TypeScript knows that "action" has only "index" but not "content"
        console.log(action.index);
        break;
    default:
    }
}
.

에 답하십시오

인터페이스에서 인스턴스를 지원하지도 않습니다.

이유는 유형 삭제입니다.인터페이스는 컴파일 유형 구성이며 런타임 영향이 없습니다.그러나 Classes 예제에서는 인스턴스를 사용할 수 있습니다.:

class Foo{}
var x = new Foo();
console.log(x instanceof Foo); // true
.

@thsoft의 훌륭한 답변 대안이 있습니다.플러스 측면 에서이 대안

  1. { type : string } & T의 형태가 T의 값에 따라 다르므로 type 형식의 원시 JavaScript 오브젝트와의 잠재적 인 상호 운용성을 가지고 있습니다.
  2. 는 실질적으로 선택할 수있는 보일 러 플레이트가 있습니다.
  3. 음수 쪽

    1. 는 모든 경우와 일치하는 모든 경우에 정적으로 시행되지 않습니다.
    2. 는 서로 다른 ADT를 구별하지 않습니다.
    3. 다음과 같습니다 :

      // One-time boilerplate, used by all cases. 
      
      interface Maybe<T> { value : T }
      interface Matcher<T> { (union : Union) : Maybe<T> }
      
      interface Union { type : string }
      
      class Case<T> {
        name : string;
        constructor(name: string) {
          this.name = name;
        }
        _ = (data: T) => ( <Union>({ type : this.name, data : data }) )
        $ =
          <U>(f:(t:T) => U) => (union : Union) =>
              union.type === this.name
                ? { value : f((<any>union).data) }
                : null
      }
      
      function match<T>(union : Union, destructors : Matcher<T> [], t : T = null)
      {
        for (const destructor of destructors) {
          const option = destructor(union);
          if (option)
            return option.value;
        }
        return t;
      }
      
      function any<T>(f:() => T) : Matcher<T> {
        return x => ({ value : f() });
      }
      
      // Usage. Define cases.
      
      const A = new Case<number>("A");
      const B = new Case<string>("B");
      
      // Construct values.
      
      const a = A._(0);
      const b = B._("foo");
      
      // Destruct values.
      
      function f(union : Union) {
        match(union, [
          A.$(x => console.log(`A : ${x}`))
        , B.$(y => console.log(`B : ${y}`))
        , any (() => console.log(`default case`))
        ])
      }
      
      f(a);
      f(b);
      f(<any>{});
      
      .

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top