React Junior
207 subscribers
37 photos
462 links
Изучение React с нуля
加入频道
Forwarded from TypeScript Challenge
Type Challenges #12. Chainable Options

Ссылка на задачу
Ссылка на песочницу с тестами

Условие

У нас есть некий объект/класс с двумя методами: option(key, value) и get(). В первый можно передать имя поля (строка) и любое значение для него. Таким образом мы "набираем" себе объект с нужными полями. Причем вызовы метода option можно объединять в цепочку (чейнить). Метод get возвращает этот "собранный" объект.


declare const config: Chainable

const result = config
.option('foo', 123)
.option('name', 'type-challenges')
.option('bar', { value: 'Hello World' })
.get()

interface Result {
foo: number
name: string
bar: { value: string }
}


Задача: типизировать класс Chainable.

Важный момент: нельзя два раза передать в option одно и то же свойство.

Решение

Тут нам нужно решить две задачи:
- сохранять переданные ключи и значения, чтобы набрать нужный тип и вернуть его в get - для этого сделаем Chainable дженериком и будем просто дописывать новые данные
- запретить передавать один ключ дважды - для этого будем проверять, если ли у нас уже такой ключ и возвращать never если нет


type Chainable<T = {}> = {
option: <K extends string, V>(
key: K extends keyof T ? never : K,
value: V
) => Chainable<Omit<T, K> & Record<K, V>>;
get: () => T;
}


#medium
👍2
Forwarded from TypeScript Challenge
Type Challenge #1042. IsNever

Ссылка на задачу
Ссылка на песочницу с тестами

Условие

Реализовать утилиту IsNever<T>, которая возвращает true, если в качестве аргумента получает never. В остальных случаях возвращает false.

Решение

Очень важная задачка, так как она затрагивает тему "распределенных" условных типов (описание в документации). Когда у нас есть дженерик с условным типом (extends) и он получает в качестве параметра union, он себя ведет "распределенно", то есть применяется к каждому элементу объединения.

И тут мы иногда имеем странные вещи:

// тут все нормально (без дженериков)
type A = never extends never ? 'yes' : 'no'
let a: A // a: 'yes'

// а тут что-то пошло не так
type B<T> = T extends never ? 'yes' : 'no'
let b: B<never> // b: never


Штука в том, что распределенный условный тип B ожидает union, а получает never, который интерпретирует как пустой union - и вообще не выполняется.

Есть лайфхак, чтобы отменить распределенное поведение: обернуть обе части условного типа в квадратные скобки:

type B<T> = [T] extends [never] ? 'yes' : 'no'
let b: B<never> // b: 'yes'


Зная это, решение составить очень просто:

type IsNever<T> = [T] extends [never] ? true : false


#medium
👍2