Первая проблема заключается в том, что сигнатура реализации перегруженной функции может быть более свободной, чем любая из сигнатур вызова. А внутри реализации компилятор проверяет только сигнатуру реализации. Это означает, что внутри вашей функции foo
и bar
оба независимо от типа boolean | undefined
, и нет способа восстановить тот факт, что любой, кто вызывает метод, будет указывать либо оба, либо ни то, ни другое.
TypeScript недавно добавил поддержку кортежей отдыха / распространения в параметрах функций , поэтому вы можете переписать сигнатуру функции следующим образом:
declare function method(...args: [] | [boolean, boolean]);
method(); // okay
method(false); // errror
method(true, false); // okay
Теперь TypeScript знает, что от args
до method()
являются либо пустым кортежем, либо парой значений boolean
. Вы можете сохранить перегрузки, если хотите, и просто сузить сигнатуру реализации:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean]) {
const foo = args[0];
const bar = args[1];
if (foo === true || foo === false) {
const result = bar; // oops, still boolean | undefined
}
}
К сожалению, вывод по-прежнему не работает, и это вторая проблема: анализ потока управления в TypeScript просто не такой умный, как мы. В то время как мы понимаем, что тип foo
коррелирует с типом bar
, компилятор этого не делает. Если сужается foo
, но он забыл, что bar
имеет какое-либо отношение к foo
. Один из способов исправить это - не разбивать foo
и bar
на отдельные типы, а вместо этого использовать защиту типа доступа к свойствам в одной переменной args
. Когда args
сужается от [] | [boolean, boolean]
до [boolean, boolean]
, вы можете быть уверены, что второй элемент определен:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean]) {
if ('0' in args) {
const result = args[1]; // boolean
}
}
Это может быть слишком много изменений кода, и IntelliSense не стоит этого для вас. Если это так, и вам удобнее быть умнее компилятора, вы можете просто использовать утверждение типа и двигаться дальше со своим днем:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(foo?: boolean, bar?: boolean) {
if (foo === true || foo === false) {
const result = bar as boolean; // I'm smarter than the compiler ?
}
}
Хорошо, надеюсь, это поможет; удачи!