GOOGLE ADS

среда, 13 апреля 2022 г.

Сопоставленный тип дает неожиданные результаты при создании из универсального типа

Я использую статические объекты для описания определений контрактов и пытаюсь генерировать типы на их основе. Эти контракты могут дополнительно иметь некоторые опции, которые я хочу описать, используя массив имен опций. Затем я хочу использовать этот массив для создания типа для передачи значений параметров. Все параметры должны быть обязательными. См. следующий код:

const definition = { optionNames: ['a', 'b'] as const }
type OptionNames = typeof definition['optionNames'][number]
// type OptionNames = "a" | "b"
type Options = Record<OptionNames, string>
// type Options = {
// a: string;
// b: string;
// }

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

interface Definition { optionNames?: readonly string[] }
type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = T2 extends string | number | symbol? Record<T2, string>: {}
type GenericOptions = ConstructOptions<typeof definition>
// type GenericOptions = Record<"a", string> | Record<"b", string>

Я ожидаю, что GenericOptions будет таким же, как и Options, однако в результате получается объединение записей, каждая из которых имеет только 1 из опций в качестве требуемого ключа. Почему это происходит?


Решение проблемы

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

type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = [T2] extends [string | number | symbol]? Record<T2, string>: {}

Полный пример:

const definition = { optionNames: ['a', 'b'] as const }
interface Definition { optionNames?: readonly string[] }
type ConstructOptions<T1 extends Definition, T2 = T1['optionNames'][number]> = [T2] extends [string | number | symbol]? Record<T2, string>: {}
type GenericOptions = ConstructOptions<typeof definition>;

Странная вещь, о которой вы, вероятно, никогда не подумали бы, но она работает. Здесь только TypeScript ✌️.

Детская площадка

Кстати, вы можете исправить эту ошибку там с помощью NonNullableили Required;)

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

Отправить комментарий

Laravel Datatable addColumn returns ID of one record only

Я пытаюсь использовать Yajra Datatable для интеграции DataTable на свой веб-сайт. Я смог отобразить таблицу, но столкнулся с проблемой. В по...