Дискриминированный союз TypeScript - переменная, используемая до назначения после исчерпывающих операторов If - PullRequest
0 голосов
/ 08 мая 2020

Я пишу код, используя функцию различимого объединения TypeScript. Я полностью проверяю свойство «тип» для каждого типа в структуре if-else if и назначаю переменную с помощью logi c в каждом блоке. Затем я возвращаю переменную. Однако я получаю сообщение об использовании возвращаемой переменной до ее назначения. Код следует этой структуре (это действительно простой пример, демонстрирующий проблему, поскольку мой реальный код намного сложнее):

interface One
{
  num   : "one";
  value : string;
}

interface Two
{
  num   : "two";
  value : number;
}

interface SomeComplexObject
{
  // Complex properties
}

type Num  = One | Two;

function isOne(
  obj : Num
) : SomeComplexObject
{
  let complex : SomeComplexObject;

  if (obj.num === "one")
  {
    // Create a complex object with one set of parameters
  }
  else if (obj.num === "two")
  {
    // Create a complex object with a second set of parameters
  }

  return complex;
}

Моя первая мысль заключалась в том, чтобы добавить последний else, чтобы выдать сообщение об ошибке что (в данном случае) значение для num недопустимо, но поскольку другие условия являются исчерпывающими, obj имеет тип never и не может быть использован.

Я мог бы выбросить super generi c, и покончить с этим, но мне интересно, почему компилятор считает, что complex может быть неопределенным, но в то же время признает, что условия являются исчерпывающими. Что-то мне не хватает?

Edit : Мой исходный пример, похоже, вызвал некоторую путаницу. Я обновил его, чтобы, надеюсь, лучше представить реальную проблему.

1 Ответ

0 голосов
/ 09 мая 2020

Я обрабатываю такого рода сценарии ios одним из двух способов. Обычно go с исчерпывающим переключателем.

interface One {
  num   : "one";
  value : string;
}

interface Two {
  num   : "two";
  value : number;
}

interface SomeComplexObject {
  // Complex properties
}

type Num = One | Two;

// Exhaustive Switch
function isOne(obj : Num) : SomeComplexObject {
    let complex: SomeComplexObject;

    switch (obj.num) {
        case "one":
            complex = {};
        case "two":
            complex = {};
    }

    return complex;
}

// Cast obj to any in `never` case
function isOne2(obj : Num) : SomeComplexObject {
    let complex: SomeComplexObject;

    if (obj.num === "one") {
        complex = {};
    } else if (obj.num === "two") {
        complex = {};
    } else {
        throw new Error(`Unknown object type ${(obj as any).num}`)
    }

    return complex;
}

Typescript Playground

...