Определение локальных типов без ошибок несовместимости в TypeScript - PullRequest
0 голосов
/ 18 марта 2020

Версия TypeScript: 3.8.2

Условия поиска: карта, окончание, тип, результат, ключи, извлечение

Код

У меня прекрасно работает следующий помощник:

export type ComputeUnionValue<V extends AnyCodec[]> = {
  [i in Extract<keyof V, number>]: GetValue<V[i]>;
}[Extract<keyof V, number>];

Я пытаюсь упростить этот помощник, который использует Extract<keyof V, number> в двух местах.

export type ComputeUnionValue<V extends AnyCodec[], E = Extract<keyof V, number>> = {
  [i in E]: GetValue<V[i]>;
}[E];

E из [i in E] ошибок с:

Type 'E' is not assignable to type 'string | number | symbol'.
  Type 'E' is not assignable to type 'symbol'.ts(2322)

и V[i] ошибок с:

Type 'V[i]' does not satisfy the constraint 'AnyCodec'.
  Type 'V[E]' is not assignable to type 'Codec<VType, unknown>'.
    Type 'AnyCodec[][E]' is not assignable to type 'Codec<VType, unknown>'.ts(2344)

и

Type 'i' cannot be used to index type 'V'

Я использую E = для того, чтобы этот новый тип находился в области видимости ... не как необязательный аргумент. Но тот факт, что это необязательный аргумент, похоже, влияет на так называемые «гарантии», что приводит к несовместимости, описанной выше. Есть ли способ создать тип E - локально для этого типа утилиты - таким образом, чтобы не было возможности несовместимости типов?

1 Ответ

1 голос
/ 18 марта 2020

Хотя я видел параметры типа, используемые как «переменная локальных типов», я не думаю, что это хорошая идея, потому что они в основном выставляют внутренние логики c извне (ведь кто-то может вместо этого передать E использования по умолчанию). Они также означают, что пользователь должен знать, какие параметры являются «реальными», а какие просто «локальными», что, на мой взгляд, является плохим DX. (К вашему сведению: на GH было предложение разрешить псевдонимы локальных типов, но я не думаю, что он никуда не делся)

При этом причина, по которой вы получаете ошибку, заключается в том, что = просто предоставляет значение по умолчанию для параметра типа, но параметр типа может иметь ЛЮБОЙ тип, включая тип, который нельзя использовать в отображаемом типе.

Решение простое, если немного подробное, предоставить значение по умолчанию и ограничение (используя extends) для параметра типа:

export type ComputeUnionValue<V extends AnyCodec[], E extends Extract<keyof V, number> = Extract<keyof V, number>> = {
  [i in E]: GetValue<V[i]>;
}[E];

Playground Link

...