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

#typescript

#typescript

Вопрос:

Возьмите функцию с двумя перегрузками сигнатур:

 type f64 = number;

function add(): f64;
function add(x: f64, y: f64): f64;
function add(x?: f64, y?: f64): f64 {
    return typeof x === "number"
        ? x   y
        : 0;
}
 

Для пояснения, приведенный выше код завершается ошибкой при попытке добавления, что y потенциально undefined возможно.

Но, если x это число, то, по расширению, параметр также y должен быть числом, поскольку нет перегрузок, которые позволяют x быть числом, не будучи y также числом.

Могу ли я заставить TSC сделать вывод / понять это без избыточной двойной проверки: typeof x === "number" amp;amp; typeof y === "number" ?

Обратите внимание, что на самом деле попытка вызвать его подобным образом недопустима:

 add(1, undefined);
 

Сбой с:

Аргумент типа ‘undefined’ нельзя присвоить параметру типа ‘number’.(2345)
Вызов был бы успешным для этой реализации, но сигнатуры перегрузок реализации не видны извне.

У меня был класс с двумя перегрузками, первый не принимал никаких параметров, другой принимал два параметра разных типов. Изначально он был написан на JS, но для его преобразования в TS потребуется реструктуризация или дополнительные утверждения, которые, я считаю, не нужны.

Ссылка на игровую площадку TS

С сайта TS:

Типы предоставляют способ описания формы объекта, предоставляя лучшую документацию и позволяя TypeScript проверять правильность работы вашего кода.

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

Изменение реализации уже работающего кода в соответствии с TS исключено из таблицы.


Обновление, самое близкое, что я получил, это:

 function add<T extends f64 | undefined>(x: T, y: T extends f64 ? f64 : never): f64 {
    return typeof x === "number"
        ? x   y
        : 0;
}

add(1, 2); // okay

add(); // expected 2 params

add(undefined); // must be (undefined, never)
 

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

1. x?: number означает x необязательный параметр типа number | undefined .

2. @AluanHaddad В этом нет ничего нового для меня. Есть ли что-нибудь, что подразумевало иное? Есть ли у вас лучшее решение для этого, чем опубликованное в настоящее время?

3. Я хочу сказать, что тип x ничего не говорит о наличии y

4. @AluanHaddad f64? используется только для соблюдения перегрузок, есть ли другой способ сделать это? Может быть, универсальные и троичные файлы?

5. Возможно return x ?? 0 y ?? 0 . Я согласен, что это досадная проблема, потому что мне не нравится изменять логику реализации только для удовлетворения типов

Ответ №1:

Первый подход

 type f64 = number;

function add(...args: []): f64
function add(...args: [x: number, y: number]): f64

function add(...args: [x: number, y: number] | []): f64 {
  if (args.length === 2) {
    const [x, y] = args;
    return x   y
  }
  if (args.length === 1) { } // expected error

  return 0
}

const result = add() // ok
const result1 = add(1) // expected error
const result2 = add(1, 2) // ok
const result3 = add(1, 2, 3) // expected error
 

Второй подход

 type f64 = number;

function add(): f64;
function add(x: f64, y: f64): f64;
function add(x?: f64, y?: f64): f64 {
  return x amp;amp; y
    ? x   y
    : 0;
}

const result = add() // ok
const result1 = add(1) // error
const result2 = add(1, 2) // ok
const result3 = add(1,undefined) // error
const result4 = add(0,0) // ok
 

Третий подход

 declare const memory: ArrayBuffer;
declare function allocate(): number;

class UintArr extends Uint8Array {
    constructor(); // overload 1
    constructor( // overload 2
        buffer: ArrayBuffer,
        byteOffset: number
    );
    constructor(
        buffer?: ArrayBuffer,
        byteOffset?: number
    ) {
        const ptr = buffer === memory // just add |undefined or remove explicit types at all
            ? byteOffset // overload 1
            : allocate(); // overload 2

        super(memory, ptr, 16);
    }
};
 

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

1. Я обновлю сообщение прямо сейчас, но add(0, 0) будет ошибкой для вашего второго метода, не так ли?