泛型与类型关联
让可复用逻辑保留输入之间及输入与输出之间的类型关系。
本章目录CONTENTS ↓
一个通用属性读取函数既要限制合法键,又要保留“选中哪个键,就返回哪个属性类型”的关系。泛型通过类型参数记录这种关联,使同一段逻辑能够复用于不同输入。
为什么需要泛型记录对象与键的关系
通用属性读取函数需要同时做到两件事:键必须存在,返回类型还要随本次选中的键变化。只把返回类型写成全部属性值的联合,会让读取一个明确字符串字段的调用也得到数字、布尔值等无关可能性。
泛型参数用于记录输入之间、输入与输出之间的关系:T 对应对象,K 对应这次选中的键,再用 T[K] 表达结果。这样的函数适合不同对象共用读取逻辑;若只是固定对象的一次访问,直接写对象属性即可,不需要额外包装一个泛型函数。
让选中的键决定返回类型
function readProperty<T, K extends keyof T>(
obj: T, key: K
): T[K] {
return obj[key];
}
const settings = { theme: "dark", retries: 3, offline: false };
const theme = readProperty(settings, "theme"); // stringT 关联对象类型,K 关联本次键实参的类型,T[K] 取对应属性的值类型。这里普通对象的 theme 属性推导为 string。
把这次调用拆成四步:
- 实参静态类型:
settings包含theme: string、retries: number、offline: boolean。 - 推导:
T采用该对象类型,K在本次调用中为字面量类型"theme"。 - 约束:
"theme"满足keyof T的合法键范围。 - 求值:
T["theme"]得到string。
K extends keyof T 限制 K 的合法范围,并不要求 K 等于全部键。上述步骤描述本例的理解路径,不是编译器所有推断场景的完整算法。
键实参是联合时
const key: "theme" | "offline" =
Math.random() > 0.5 ? "theme" : "offline";
const value = readProperty(settings, key);
// K = "theme" | "offline"
// T[K] = T["theme"] | T["offline"]
// = string | boolean编译期只知道 key 可能是这两个键,因此返回值也是对应两种类型的联合。它不会等运行时选中键后再决定泛型类型。
为什么只有 keyof T 还不够
function readLoose<T>(obj: T, key: keyof T): T[keyof T] {
return obj[key];
}
const loose = readLoose(settings, "theme");
// string | number | boolean这个返回类型始终包含全部属性值,没有独立的 K 记录本次键类型。
官方阅读
- Generics:类型参数与约束。
- Indexed Access Types:由键取得属性值类型。
这一页,先记到这里。