Можно ли обнаружить ненужные охранники типа? - PullRequest
3 голосов
/ 15 января 2020

У меня есть следующий код Typescript:

type Nothing = undefined | null;
export const isNothing = <T>(val: T | Nothing): val is Nothing =>
  val === null || typeof val === 'undefined';

isNothing - это защита типа, которая в основном проверяет, установлено или нет значение.

Мне бы хотелось для обнаружения следующего перед выполнением:

const foo:number = 42;
if(isNothing(foo)) { /* ... */ }

Дело в том, что защита типа является избыточной. Поскольку foo явно введено, это не может быть null или undefined.

Я пытался найти ответы в следующих строках:

  • Перегрузка isNothing для возврата типа never, если val не является типом объединения
  • Некоторое правило линтера, которое помечает, когда параметр функции, которая принимает объединение, не является объединением (это похоже на подход кувалдой).
  • Некоторое правило линтера, которое явно обнаруживает ненужные средства защиты типов

В этом случае «обнаружение» будет либо ошибкой времени компиляции, либо уведомлением линтера. Важно отметить, что это будет обнаружение перед выполнением.

Ответы [ 2 ]

1 голос
/ 16 января 2020

Я закончил с этим:

type Nothing = undefined | null;

export function isNothing<T>(val: NonNullable<T>): never
export function isNothing<T>(val: T | Nothing): val is Nothing
export function isNothing<T>(val: T) { return val === null || typeof val === 'undefined'; }

Затем я установил strict-boolean-expressions в true в моей конфигурации TSLint.

В результате мой линтер теперь перехватывает всякий раз, когда переменная явного типа, которая не содержит null или undefined, передается в эту функцию.

1 голос
/ 15 января 2020

Как я объяснил в комментариях выше, не существует такого решения, которое само по себе защитит тип, будет препятствовать компиляции кода, если проверка избыточна. Я думаю, что под термином «объединение типов» вы подразумеваете в этом особом случае переменную, которая не является нулевой и не неопределенной, и поэтому проверка защиты типа isNothing будет избыточной.

Решением будет принудительная компиляция чтобы убедиться, что переменная «может быть нулевой или неопределенной», прежде чем вызывается охрана типа isNothing:

type Nothing = undefined | null;

export const isNothing = <T>(val: T | Nothing): val is Nothing =>
  val === null || typeof val === 'undefined';


let a!: number;
let b!: number | undefined;
let c!: undefined;
let d!: null;

function assertMaybeNothing<T extends (Exclude<T, Exclude<T, undefined | null>> extends never ? never : any)>(arg1: T) {
  return true;
}

assertMaybeNothing(a); // error because is never undefined or null
assertMaybeNothing(b);
assertMaybeNothing(c);
assertMaybeNothing(d);

if (assertMaybeNothing(a) && isNothing(a)) {
  let x = a;// is never
} 

Playground Link

...