Как стать автором
Обновить
4
0.2
Отправить сообщение

Если речь об этом, то такая проблема не только в интерфейсах, но и в типах и даже, как ни прискорбно, в классах

{} - это не "пустой объект", а "что угодно, кроме null и undefined". В переменную х можно воткнуть любое значение, кроме этих двух.

Передаваемый объект соответствует типу А по правилам TS, значит соответствует и типу A | B

В моем примере A | B вообще должно схлопнуться до A, потому что B - подтип A. Но даже если и не был подтипом, всё равно проверка недостаточна.

Ну, например, что в виде параметра может закатиться объект с полем y, которое не number, а TS уверен, что проверки на наличие поля достаточно. Результат можно увидеть, нажав кнопку Run.

Да и в структурной типизации TS хватает всякого странного, например вот

Но, кажется, сам по себе промис определен именно в спецификации языка. Т.е. среда выполнения обязана предоставить микротаски для колбэков then (обычные таски, которые "макро", на голом js создать не из чего, а вот зарезолвленный промис - вполне).

Да, согласен. Поскольку здесь any требуется для бивариантности параметра, то ещё можно это указать явно:

type Guard<P = unknown, T extends P = P> = {f(x: P): x is T}['f'];

а в SomeOf уже добавить проверку для P. И never в типе SomeOf я бы поменял на (x: never) => x is never, чтобы нельзя было передать в тот же Array.filter или ещё куда. Итого:

type Guard<P = unknown, T extends P = P> = {f(x: P): x is T}['f'];
type Param<F> = [F] extends [(x: infer P) => unknown] ? P : never;

type SomeOf<T extends Guard[]> =
  T[number] extends Guard<infer P extends Param<T[number]>, infer R>
    ? (x: P) => x is R
    : (x: never) => x is never;

function someOf<T extends Guard[]>(...guards: T) {
    return ((x: never) => guards.some(guard => guard(x))) as SomeOf<T>;
}

----

Вообще типизация метода Array.filter вызывает вопросы. Например, вот такой простой кейс:

const numArr: (1 | 2 | 3)[] = [];
const guard = (x: number): x is 3 | 4 => true;
const filtered = numArr.filter(guard); // (2 | 1 | 3)[]

Здесь filtered по логике должен быть 3[], но увы. Кажется, правильнее было бы как-то так:

filter<S>(predicate: (value: S | Exclude<T, S>) => value is S, thisArg?: any): (S & T)[];

и тогда по идее мои поправки из первого поста будут лишними.

Я допускаю, что это плохо в некоторых отдельных случаях. Но по поводу "всегда" интересно увидеть обоснование.

В тех случаях, где с передачей объектов возникнут проблемы, можно передавать id. Но вовсе не потому, что инструмент, видите ли, без этого не может нормально работать.

Добавлю, что при таком подходе компонент становится более автономным, не завязанным на глобальный стор, и легче тестируемым. Впрочем, это наверно очевидно...

Да, нормализация данных, я уж и подзабыл) Но тогда это в копилку лишнего бойлерплейта, разве нет? Мы вынуждены нормализовывать, а в мобх можно обойтись просто массивом объектов.

Ну вот такой классический кейс: допустим, в вашем примере верстка поста уехала в отдельный компонент Post. При изменении какого-то поля отдельного поста, мобх может обойтись ререндером одного Post, а редукс вынужден дополнительно ререндерить список

Интересная статья, спасибо.

Применение any вместо never в качестве типа по умолчанию — вынужденная необходимость из-за ограничения T extends P, вытекающего из природы тайпгарда

можно заменить на unknown

В нашей реализации есть что улучшать. Например, можно попробовать ввести обобщенный тип S, как и в других примерах, чтобы на этапе компиляции отсекать бессмысленные проверки, которые априори ведут к пустому массиву.

Это стоит сделать, потому что прямо сейчас добавление "лишнего" пункта в someOf молча ломает типизацию, и фильтр перестает работать в режиме тайпгарда. Если в самом последнем примере добавить в копилку, допустим, is(2), то filtered будет Event[]

Допилил этот кейс, небольшие изменения в строках 41-48

в этом примере несколько другое. А именно, что конкретно брать за "N" в О-большом. Если длину стороны матрицы, то так и будет O(N^2)

Только если соседние элементы различаются на единицу. В задаче нет такого условия.

Правило 4 применимо для простого кейса - когда сложность внутреннего цикла не зависит от текущей итерации внешнего. Если зависит, то придется аккуратно просуммировать сложности, и там может выйти по разному. Например, в пузырьковой сортировке так и остается O(N^2), а вот для того же heapify внезапно оказывается O(N)

Можете кинуть ссылку на Playground с ошибкой?

Не очень понял, как это можно использовать.

Ну, например, GetWithArray < ProductionObject, ['versions', 'length'] > должен быть number - берем длину массива.

Я тут слегка поправил своё решение, точнее ExtractFromObject . В предыдущем были косяки с кортежами и массивами:

1) для кортежа ключ number возвращал все свои значения без undefined, а должен с ним.

2) неправильно работало с ключами-объединениями для массивов (см. примеры в extendedCases), в том числе never. Ключи never срезают всё кроме null и undefined, т.к. эти двое не индексируются.

3) для массива ключ never возвращал все его значения (думаю, это баг TS), а должен вернуть never, как в объектах

Я вот так решил:

type ExtractFromObject<O, K> = [never[], K] extends [O, number | `${number}`]
  ? O[number & keyof O] | undefined
  : K extends keyof O ? O[K] : undefined;

type GetWithArray<O, K> = O extends null | undefined
  ? O
  : K extends readonly []
    ? O
    : K extends readonly [infer Key, ...infer Rest]
      ? GetWithArray<ExtractFromObject<O, Key>, Rest>
      : never;

У вас не совсем правильно работает на массивах, например, у массивов есть свойство 'length', которое должно быть number.

Выкидывать null и undefined можно с помощью типа NonNullable < T >, который под капотом просто T & {}. Почему так? Потому что {} - это "всё кроме null и undefined"

вызов showSuccess и showFailure ошибочно соседствуют рядом с декларативным подходом

Специально для этого кейса у хука useQuery есть целых 3 параметра - onError, onSettled, onSuccess

1
23 ...

Информация

В рейтинге
2 092-й
Откуда
Москва, Москва и Московская обл., Россия
Зарегистрирован
Активность

Специализация

Frontend Developer
Senior
JavaScript
TypeScript
React
HTML
CSS
Web development
Redux
MobX
Webpack