You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript:使用Type Flavoring时不相交键类型对象可非法传递

解决Type Flavoring索引签名的兼容性问题

在使用TypeScript的类型风味(Type Flavoring)区分不同字符串键类型时,会遇到一个意外行为:类型为{[key: SomeFlavoredString]: ObjectA}的对象可以被传递给接受{[key: SomeOtherFlavoredString]: ObjectB}的函数,且编译器不报错。这是因为TypeScript认为两个不相交的键类型没有重叠,会忽略值类型的兼容性检查,将源对象视为"空对象"处理,从而埋下bug隐患。

解决方案

1. 实现精确类型检查

通过自定义工具类型强制对象的键只能属于目标索引签名的键类型,不允许存在额外的不相交键:

type Flavor<T, FlavorT> = T & { __flavor?: FlavorT };
type UserId = Flavor<string, 'userId'>;
type PostId = Flavor<string, 'postId'>;

type ObjectA = { a: string };
type ObjectB = { b: number };

// 精确类型工具:确保Obj的键完全符合Shape的键类型
type Exact<Obj, Shape> = Obj extends Shape ? keyof Obj extends keyof Shape ? Obj : never : never;

function processPosts(posts: Exact<{ [key: PostId]: ObjectB }, { [key: PostId]: ObjectB }>) {}

const users: { [key: UserId]: ObjectA } = { '123' as UserId: { a: 'test' } };
processPosts(users); // 编译器报错:类型不兼容

2. 结合唯一符号与映射类型

用unique symbol作为风味标记,让键类型的区分更严格,同时使用映射类型确保键类型完全匹配:

const USER_ID = Symbol() as unique symbol;
const POST_ID = Symbol() as unique symbol;

type UserId = string & { [USER_ID]: never };
type PostId = string & { [POST_ID]: never };

type ObjectA = { a: string };
type ObjectB = { b: number };

// 用映射类型替代索引签名,确保键类型严格匹配
type UserMap = { [K in UserId]: ObjectA };
type PostMap = { [K in PostId]: ObjectB };

function processPosts(posts: PostMap) {}

const users: UserMap = { '123' as UserId: { a: 'test' } };
processPosts(users); // 编译器报错:类型不兼容

3. 泛型函数的条件约束

在函数参数中添加条件类型约束,当源对象的键类型与目标键类型不相交时直接触发错误:

type Flavor<T, FlavorT> = T & { __flavor?: FlavorT };
type UserId = Flavor<string, 'userId'>;
type PostId = Flavor<string, 'postId'>;

type ObjectA = { a: string };
type ObjectB = { b: number };

function processPosts<T extends { [key: PostId]: ObjectB }>(
  posts: T & (keyof T extends PostId ? unknown : never)
) {}

const users: { [key: UserId]: ObjectA } = { '123' as UserId: { a: 'test' } };
processPosts(users); // 编译器报错:类型不兼容

这些方法都能强制TypeScript检查对象的键类型和值类型的完全兼容性,避免因不相交键类型导致的隐式类型兼容问题。

内容的提问来源于stack exchange,提问作者user2521651

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 05:25:20