Я не знал, как правильно сформулировать свой вопрос, поэтому приведу пример.
type ValueType = "NUM" | "STR";
type TypeOf<T>
= T extends "NUM" ? number
: T extends "STR" ? string
: never;
interface TypedValue<T = ValueType> {
type: T;
data: TypeOf<T>;
}
// Compiles, as intended
const test1: TypedValue = { type: "NUM", data: 123 };
// Does not compile, as intended
const test2: TypedValue<"NUM"> = { type: "NUM", data: "123" };
// Should not compile, but does...
const test3: TypedValue = { type: "NUM", data: "123" };
Кажется, что Typescript генерирует много конкретных типов для интерфейса TypedValue
:
так
interface TypedValue<T = ValueType, D = TypeOf<T>>
соответствует
interface TypedValue<"NUM", number>
interface TypedValue<"NUM", string>
interface TypedValue<"NUM", never>
interface TypedValue<"STR", number>
interface TypedValue<"STR", string>
interface TypedValue<"STR", never>
и, может быть, больше, хотя я на самом деле хочу, чтобы этот универсальный тип соответствовал просто
interface TypedValue<"NUM", number>
interface TypedValue<"STR", string>
Как мне избежать такого распределения типов, например, Как я могу связать один параметр типа с другим параметром типа в машинописи?
Я знаю о том, как подавить распределение типов с помощью
type TypeOf<T>
= [T] extends ["NUM"] ? number
: [T] extends ["STR"] ? string
: never;
Но я не могу решить головоломку сам, и я действительно хочу копнуть глубже в этой магической системе типов, поэтому любая помощь приветствуется :) Я уверен, что jcalz знает, как справиться с этим;)
РЕДАКТИРОВАТЬ Это наконец щелкнуло после ответа Тициана Черникова-Драгомир! Лично я лучше понимаю решение с помощью следующего фрагмента кода:
type Pairs1<T> = [T, T];
type Pairs2<T> = T extends (infer X) ? [X, X] : never;
type P1 = Pairs1<"A" | "B">; // => ["A" | "B", "A" | "B"]
type P2 = Pairs2<"A" | "B">; // => ["A", "A"] | ["B" | "B"]
Что, похоже, и происходит, компилятор Typescript проверит T extends (infer X)
для каждого члена объединения "A"|"B"
, который всегда выполняется успешно, но теперь он связывает переменную соответствующего типа с переменной типа non-union X
. И infer X
на самом деле не нужен, но это помогло мне лучше понять его.
Бесконечная благодарность, я давно с этим борюсь.
Итак, теперь я наконец понимаю следующую выдержку из руководства Typescript:
В экземплярах распределительного условного типа T extends U ? X : Y
ссылки на T
в условном типе разрешаются до отдельных составляющих типа объединения (т. Е. T
относится к отдельному человеку составляющие после условного типа распределяются по типу объединения). Кроме того, ссылки на T
в X
имеют дополнительное ограничение параметра типа U
(т. Е. T
считается присваиваемым U
в X
).