Комментарии 23
С одной стороны тайпскрипт является хорошей попыткой типизировать JS, закрывая один пласт проблем, но с другой стороны вносит другой пласт проблем поверх и так проблемного JS. Смотря на подобные вещи и на ошибки в багтрекере, понимаешь что это хождение по тонкому льду. Может это только моё субъективное мнение, но ощущается это именно так.
Выглядит как магия.
У нас по этому поводу в компании ходит шутка: 'В коде не должно быть никакой магии, а волшебство — пожалуйста'
Автору поста тогда вопрос, как нормально реализовать типы, когда приналичии одного из передаваемых пропсов можно использовать и другие. Например мы хотим давать возможность устанавливать цвет рамок, только если в передаваемых пропсах так же указано, что мы вообще хотим использовать рамку. Самому ответ кажется очевидным, да и он есть в примерах, но при большом количестве наследуемых типов теряется подсветка в ide, а значит толку от таких типов не много.
Я не автор, но попробую ответить.
Насколько я понимаю, TS не работает с отдельными частями интерфейса, а лишь "дискриминирует" состояние целиком. (Изначально union это как бы квантовое состояние, которое коллапсирует с каждым новым ограничением, но лишь целиком, пока не остается статический тип)
Таким образом, сделать это можно юнионом как в примерах, но это приводит к комбинаторному взрыву состояний… (у IDE обычно ограничения глубины для комфорта работы, а компиляция просто будет все дольше и дольше)
И того нам остается:
- Использовать под интерфейсы. Меняя структуру данных.
- Делать юнионы, при разумных количествах комбинаций.
- Забить.
Находка: Восклицательный знак в роли Non-null assertion operator
Это вредный совет, рано или поздно вы по невнимательности наткнетесь на проверку number или string таким образом и получите баг. Лучше запретить использование небулевого выражения в булевом контексте с помощью tslint.
На тайпскрипте можно написать ограниченный итератор (на 40 шагов), что позволяет делать некоторые крутые штуки
github.com/pirix-gh/ts-toolbelt/blob/master/src/Tuple/Drop.ts
как пример
Кажется это можно использовать для такой задачи
[{key: 'a', value: 'b'}, {key: 'b', value: 'c'}] в {a: 'b', b: 'c'}
Это ирония или я чего-то не понимаю? Чем плох reduce?
[{key: 'a', value: 'b'}, {key: 'b', value: 'c'}].reduce((acc, elem) => ({ ...acc, [elem.key]: elem.value }), {})
type arr = [{key: 'a', value: 'b'}, {key: 'b', value: 'c'}];
type obj = {
[K in arr[number]['key']]: Extract<arr[number], {key: K}>['value']
};
const obj: obj = {a: 'b', b: 'c'} // ошибки нет
const wrong1: obj = {}; // не хватает параметров
const wrong2: obj = {a: 'b', b: 'c', c: 'd'} // параметр c лишний
const wrong3: obj = {a: 'b', b: 1} // параметр b не того типа
Что я делаю не так?
upd: хабр, запили подсветку TS ><
С другой стороны, там очень сильно перемудрили. Например, вместо типа true ввели тип True=1. Аналогичные обёртки запилили над всеми типами. Или вместо двух обобщённых типов понавтыкали один с флагом. Или вкорячили арифметику для чисел от -40 до 40. Короче, как источник идей как типизировать что-то хитрое типа Compose использовать можно, но тянуть в проект такое я бы поостерёгся.
Кажется это можно использовать для такой задачи
Если Вы говорили конкретно про Drop, а не про библиотеку, то это не совсем верно. Drop нужен для исключения первых элементов кортежа.
type List = [number, string, boolean, undefined];
type DroppedList1 = Drop<MyList, 1>; // [string, boolean, undefined]
type DroppedList2 = Drop<MyList, 2>; // [boolean, undefined]
https://www.freecodecamp.org/news/typescript-curry-ramda-types-f747e99744ab/
В этой статье есть много про паттерны для работы с кортежами.
Например, попробовал сделать маппер, с полной поддержкой TS
interface MyMapper<F, T, TK extends keyof T> {
field: keyof F;
map: IMapScheme<F, T[TK]>;
}
type IMapScheme<F, T> = {
[TK in keyof T]: keyof F | MyMapper<F, T, TK>;
};
interface From {
_id: string;
name: string;
data: {
foo: string;
bar: string;
};
}
interface To {
id: string;
name: string;
meta: {
fooData: string;
};
}
const Try1Scheme: IMapScheme<From, To> = {
id : '_id',
name: 'name',
meta: {
field: 'data',
map : {
fooData: 'foo',
},
},
};
И очень просится написать что-то на подобии
interface MyMapper<F, T, TK extends keyof T> {
field: keyof F;
map: IMapScheme<F[this.field], T[TK]>;
}
Такая магия возможна?
Не очень понял зачем вам эти типы. Просто напишите функцию-маппер и возльмите от неё typeof.
Объект именно потому что несколько таких объектов можно потом склеить, в специфике этого приложения это крутая фича.
И мне интересно, может ли его валидность проверить сам TS.
А про функцию — задача эта уже решена, но хотелось бы ее решить красиво.
Впрочем, не только у TypeScript, но и у Java habr.com/ru/post/330724, и С++ и др.
TypeScript. Магия выражений