Понимание правила никогда не вводить в TypeScript 2

#typescript #typescript2.0

#typescript #typescript2.0

Вопрос:

При взгляде на то, что нового в TypeScript 2.0, я нашел never тип. Согласно документам, похоже, что это умный способ задать тип функций, которые никогда не возвращаются.

Теперь, если я все правильно прочитал, то never может быть присвоен каждому типу, но только never может быть присвоен never . Итак, при написании небольшого теста в VS Code я получил следующее:

 function generateError(){
    throw new Error("oops");
}
function do(option: "opt1" | "opt2"){
    if(option === "opt1") return true;
    if(option === "opt2 ) return false;
    generateError();
}
let res = do("blah");
  

Ну, какой ожидаемый тип res ? Согласно компилятору, это string | undefined (что имеет смысл, хотя, должен сказать, я ожидал string ). Думаю, я не вижу смысла в создании нового типа только для представления функций, которые никогда не возвращаются. Действительно ли нам нужна эта концепция? Это просто особенность компилятора, которая помогает ему проводить лучший анализ потока?

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

1. Предполагаемый возвращаемый тип скорее должен быть boolean

2. Я также рассмотрел это здесь : basarat.gitbooks.io/typescript/content/docs/types/never.html

3. @basarat эта ссылка больше никуда не ведет.

4. Обновлено : basarat.gitbook.io/typescript/type-system/never

Ответ №1:

Never — это информация о том, что эта конкретная часть не должна быть доступна. Например, в этом коде

 function do(): never {
    while (true) {}
}
  

у вас бесконечный цикл, и мы не хотим повторять бесконечный цикл. Просто так.

Но реальный вопрос в том, как это может быть полезно для нас? Может быть полезно, например, при создании более продвинутых типов указывать, чем они не являются

например, давайте объявим наш собственный ненулевой тип:

 type NonNullable<T> = T extends null | undefined ? never : T;
  

Здесь мы проверяем, имеет ли значение T значение null или не определено. Если это так, то мы указываем, что этого никогда не должно произойти. Затем при использовании этого типа:

 let value: NonNullable<string>;
value = "Test";
value = null; // error
  

Ответ №2:

Вы можете использовать never , чтобы гарантировать, что вы не пропустите контракт функции.

 function forever(): never {
    while (true) {
        break; // Error because you can't leave the function.
    }
}

enum Values {
    A,
    B
}

function choose(value: Values) {
    switch (value) {
        case Values.A: return "A";
    }

    let x: never = value; // Error because B is not a case in switch.
}
  

Ответ №3:

Функции, которые никогда (ever) не возвращаются, и функции, которые могут выдавать, — это не совсем одно и то же.

Например:

 function foo(option: "opt1" | "opt2"): string | undefined {
  if (option === "opt1") return true;
  if (option === "opt2") return false;
  throw new Error("unknown option");
}

function bar(option: "opt1" | "opt2"): never {
  while (true) {
    doOption(option);
  }
}
  

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

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

Существуют некоторые функции, которые выглядят как # 2, но на самом деле подпадают под # 1, обычно, когда throw задействована или если вы используете process.exit в node (которые не могут вернуться, поскольку они завершают процесс).

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

1. Привет, ssube. Итак, если есть шанс возврата, он не может иметь тип never . Имеет смысл. Но тогда в чем смысл never? Мне трудно понять, почему это было введено в TypeScript…

2. Цель состоит в том, чтобы явно указать методы, которые не будут возвращать, как в process.exit примере. Теперь, когда компилятор знает наверняка, размещение кода после них может выдать предупреждение, точно так же, как размещение кода после return .

3. Ах, так это дело компилятора? Тем не менее, не уверен, почему он там есть, потому что я почти уверен, что приведенные примеры, оправдывающие его существование, могут быть правильно выведены компилятором без этого типа … опять же, я могу ошибаться…

4. Как бы еще вы описали возвращаемый тип process.exit ?

5. хорошо, может быть, в таком случае … тем не менее, не уверен, где я буду использовать его в своих программах. Вероятно, через пару месяцев я передумаю…