Эксперементирую с дженериками, пытаюсь понять принцип работы.
interface MyArray<T> {
reduce<T>(fn: (arg:T) => T): T;
}
let arr = [1, 2, 3, 4, 5];
let results = arr.reduce((sum, current) => sum + current, 0);
results
В таком виде вроде все работает нормально, но если в массиве поменять одно значение на строку.
interface MyArray<T> {
reduce<T>(fn: (arg:T) => T): T;
}
let arr = [1, 2, 3, 4, '5'];
let results = arr.reduce((sum, current) => sum + current, 0);
results
Здесь sum + current появляется ошибка:
Operator '+' cannot be applied to types 'string | number' and 'string | number'
Пытался менять описание примерно так и еще несколько вариантов пробовал:
interface MyArray<T> {
reduce<T, U>(fn: (arg1:T, arg2:U) => [T,U]): [T,U];
}
let arr = [1, 2, 3, 4, '5'];
let results = arr.reduce((sum, current) => sum + current, 0);
results
Но ничего не помогает и естественно даже не уверен, что правильно делаю. Как все-таки в таком случае сделать описание дженериками в интерфейсе?
Еще вариант
type MyArray<T> = {
[N in (number | string)]: T
} & {
reduce<T>(fn: (arg: T) => T): T
}
let arr = [1, 2, 3, 4, '5'];
let results = arr.reduce((sum, current) => sum + current, 0);
results
Здесь, думаю, бага тайпскрипта. С одной стороны логично, что он тебе говорит, что "Нельзя строку или число сложить со строкой или числом" (потому что складывать надо число с числом). С другой стороны TS вполне кушает такое:
const a: string | number = 1;
const b: string | number = '2';
const z = a + b;
Он понимает, что z на выходе будет только строка (потому что число плюс строка на выходе строка).
При этом даже так работает:
interface MyArray<T> {
reduce<T>(fn: (arg:T) => T): T;
}
let arr = [1, 2, 3, 4, '5'];
let results = arr.reduce((sum, current) => 1 + '2', 0);
results
То есть мы явно складываем число и строку и ТС это не парит.
Для тебя выход: или использовать только числа, или если ты допускаешь, что могут приходить строки, но это все равно числа, то парсить их.
interface MyArray<T> {
reduce<T>(fn: (arg:T) => T): T;
}
let arr = [1, 2, 3, 4, '5'];
let results = arr.reduce<number>((sum, current) => sum + (typeof current === "string" ? parseInt(current) : current), 0);
results
Обрати внимание, что <number> в такой конструкции обязателен, потому что reduce сам по себе тоже дженерик, и в него можно передать какой тип ожидается в результате. Если ты не указываешь явно, то он берет из входящих параметров. Так как у тебя на входе массив чисел или строк, то он допускает, что sum тоже число или строка, и тоже ругается на то, что его нельзя суммировать. Указав <number> мы ему сообщаем, что результат у него четко number, и тут уже reduce будет требовать, чтобы каждая итерация у тебя возвращала четко number и будет считать, что sum тоже всегда number.
Получается мы принудительно получаем результат number и преобразуем строку в число, но по логике вычисления там включается конкатенация и результат этого выражения должен быть 105, насколько вообще правильно в данном случае так делать или это все-таки зависит от задачи?
Может можно все-таки что-то сделать не ломая логику выражения?
В моем случае нет конкатенации, потому что я складываю уже преобразованные в числа строки и у меня на выходе четко строки, то есть результат 15. В твоем же случае это походит на натягивание совы на глобус. Вот зачем тебе складывать числа со строками?
Просто интересно)
Ну вот ТС тебе говорит "Ты занимаешься фигней", и я с ним в целом согласен :)
Переходи к следующему уроку))