Защитник типа «не ноль» преобразуется в «никогда» в else-ветви - PullRequest
1 голос
/ 09 июля 2019

Я создал защиту типа, которая проверяет, является ли аргумент точно null:

function isNotNull<T> (arg: T): arg is Exclude<T, null> {
  return arg !== null
}

Когда я проверяю его, ветвь then работает правильно: она удаляет null изтип.

const value: string | null = 0 as any
if (isNotNull(value)) {
  // value is of type `string` here
}

Однако в else -выделении он становится never.

const value: string | null = 0 as any
if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `never` here
}

Я бы хотел разрешить null в else -отрасль.

Как мне этого добиться?

1 Ответ

2 голосов
/ 09 июля 2019

Проблема здесь в назначении:

const value: string | null = 0 as any

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

Не станет намного лучше, если вы используете let:

let value: string | null = 'foo';
if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `never` here
}

Опять же, компилятор машинописного текста знает, что значение не равно нулю.

Но если назначить что-то, где Typescript не может вывести постоянное значение, то у вас будет ожидаемый string в if ветви и null в else:

function isNotNull<T> (arg: T): arg is Exclude<T, null> {
  return arg !== null
}

let value: string | null = foo();

if (isNotNull(value)) {
  // `value` is of type `string` here
} else {
  // `value` is of type `null` here
}

function foo(): string | null {
    return "foo"
}

Кроме того, даже этот последний пример работает, только если для параметра компилятора strictNullChecks установлено значение true. Если вы не включили strictNullChecks, вы не можете исключить null из type, и ветвь if будет string, что совпадает с string | null, так что для else остается только never .

Edit: Причина, по которой это не работает, когда strictNullChecks выключен, довольно интересна. В этом случае типы string | null и string идентичны. Это означает, что value на самом деле имеет тип string, а Exclude<string, null> просто string (и, следовательно, по-прежнему включает null), поэтому предложение else осталось с типом never для value.

...