Как бы вы подошли к сопоставлению с образцом в TypeScript?

Какие подходы можно рекомендовать для выполнения чего-то похожего на сопоставление с образцом в TypeScript? Лучшее, что я придумал до сих пор, это дать уникальное значение "tag" для каждого интерфейса с кортежами и сделать оператор switch/case на основе этого.

interface First { tag: 'one' }
interface Second { tag: 'two' }
type Third = First | Second

function match<T>(input: Third): T {
 switch( input.tag ){
   case 'one': {
   ...
   } 
   case 'two': {
   ...
   }
   default: {
   ...
   }
 }
}

На мой взгляд, это все еще немного недружественный и непродуктивный подход к этому.

Я сам не совсем уверен, как далеко вы могли бы зайти в этом, поскольку TypeScript не является первоклассным типом, но я хотел бы попробовать.


person Jimi Pajala    schedule 06.05.2018    source источник
comment
я знаю, что это кажется раздражающим для языка, но на самом деле это не имеет большого значения, и, возможно, даже хорошо.. кроме того, кто-то может попытаться посоветовать использовать классы и instanceof, но это не будет хорошей идеей -- instanceof препятствует предоставлению хороших макетов для тестирования -- интерфейсы вместо instanceof являются сильной стороной машинописного текста   -  person ChaseMoskal    schedule 06.05.2018


Ответы (1)


возможно, используйте перечисление для этого

enum Tag {
  One,
  Two,
  Three
}

interface Taggable {
  tag: Tag
}

interface Alpha extends Taggable {
  tag: Tag.One
  a: number
}

interface Bravo extends Taggable {
  tag: Tag.Two
  b: number
}

function match<gTaggable extends Taggable = Taggable>(
  taggable: gTaggable
): gTaggable {
  switch(taggable.tag) {

    case Tag.One: {
      const {tag, a} = taggable
      // ...
      break
    }

    case Tag.Two: {
      const {tag, b} = taggable
      // ...
      break
    }

    default: {
      throw new Error(`unknown taggable "${taggable.tag}"`)
    }
  }
}

если вы чувствуете себя особенно непослушным, вы можете использовать символы вместо перечислений для таких вещей

person ChaseMoskal    schedule 06.05.2018