Код Typescript компилируется, хотя тип должен быть помечен

#typescript

#typescript

Вопрос:

У меня есть этот код для моделирования типа результата. Тип сбоя будет содержать все возможные сбои. ‘Неправильный’ не является одним из них, но я, тем не менее, могу вернуть неверный как сбой.

 type Try<T, E> = Success<T> | Failures<E> | E;

// User code

type Failure = FileNotFound | NameNotFound;

class FileNotFound extends BaseFailure {}
class NameNotFound extends BaseFailure {}

class Incorrect extends BaseFailure {}

type Result<T> = Try<T, Failure>

function y() {
  let x1 = x(1);
  if (x1.isSuccess) {
  } else {
    x1.hasMany;
  }
}

function x(a:number): Result<String> {
  if (a>3) {
    return new Success("Hallo");
  } else {
    return new Incorrect();
  }
}
  

Комментарии:

1. Не могли бы вы указать все типы в коде? Некоторые из них не включены.

Ответ №1:

Typescript использует структурную совместимость для определения совместимости типов. Поэтому, когда он решает, Incorrect совместим ли класс с Failure , он сравнивает структуру Incorrect с членами Failure объединения. Делая это, он обнаружит, что он FileNotFound имеет ту же структуру, что и Incorrect , и, следовательно, совместим.

Чтобы обойти это, вы можете добавить элемент (предпочтительно private ) ко всем классам в объединении. Это, например, приведет к сбою:

 class Success<T> { constructor(public value: T) { } isSuccess: true = true }
type Try<T, E> = Success<T> | E;

class BaseFailure {
    isSuccess: false
}

type Failure = FileNotFound | NameNotFound;

class FileNotFound extends BaseFailure { private _type: "filenotfound" }
class NameNotFound extends BaseFailure { private _type: "namenotfound" }

class Incorrect extends BaseFailure { }

type Result<T> = Try<T, Failure>

function y() {
    let x1 = x(1);
    if (x1.isSuccess) {
    } else {
    }
}

function x(a: number): Result<String> {
    if (a > 3) {
        return new Success("Hallo");
    } else {
        return new Incorrect(); // error now
    }
}
  

Вы также можете включить поле private в BaseFailure , чтобы заставить разработчиков указывать его:

 class BaseFailure<T> {
    isSuccess: false
    private __type: T
}


class FileNotFound extends BaseFailure<"filenotfound"> { }
class NameNotFound extends BaseFailure<"namenotfound"> { }

class Incorrect extends BaseFailure<"incorrect"> { }
  

Разрешение некоторой номинальной типизации уже давно обсуждалось (см. Проблему), но на данный момент это лучшее, что мы можем сделать

Комментарии:

1. Большое спасибо за ваш ответ.