【发布时间】:2019-06-04 01:55:11
【问题描述】:
我不知道如何正确地表达我的问题,所以我举个例子。
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 知道如何解决这个问题;)
编辑 Titian Cernicova-Dragomir 回答后终于点击了!我个人使用以下代码 sn-p 更好地理解解决方案:
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 编译器将为每个联合成员 "A"|"B" 检查 T extends (infer X),这总是成功,但它现在将匹配的类型变量绑定到 非联合 类型变量X。 infer X 实际上是不需要的,但它帮助我更好地理解它。
无限感激,我为此苦苦挣扎了很久。
所以现在我终于明白了Typescript手册的以下摘录:
在分配条件类型T extends U ? X : Y 的实例化中,条件类型中对T 的引用被解析为联合类型的各个组成部分(即T 指的是条件类型后的单个成分分布在联合类型上)。此外,在X 中对T 的引用有一个额外的类型参数约束U(即T 被认为可以分配给X 中的U)。
【问题讨论】:
-
jcalz 可能还在睡觉,你必须接受我的回答 :)
-
防止联合类型分布的简单通用解决方案是通过接口lorefnon.tech/2019/05/02/…将它们装箱
标签: typescript typescript-generics