如何通过tsconfig配置或ESLint规则禁止将无关类型作为函数参数传入?
这个问题我太熟了!你遇到的是TypeScript结构类型系统的典型坑——因为Product和Order恰好有共同的可选属性title?,TypeScript就默认认为它们类型兼容,但实际业务里这俩完全是不相关的类型,而且你的filterOrder函数还用到了Order独有的orderName,这就很容易埋下隐蔽的bug。
下面给你几个实用的解决办法,都是我在项目里亲测有效的:
一、给类型添加唯一标识(最直接的TypeScript语法方案)
TypeScript的结构类型系统会根据属性结构判断兼容性,那我们就给每个业务类型加一个独有的“标记”,让它无法和其他类型混淆:
方案1:使用唯一符号(Symbol)
// 给每个接口定义专属的唯一符号 const _orderMarker = Symbol(); interface Order { [_orderMarker]: never; // 这个符号属性不会影响运行,只是做类型标记 title?: string; orderName?: string; } const _productMarker = Symbol(); interface Product { [_productMarker]: never; title?: string; productId?: string; } var product: Product = {}; function filterOrder(order: Order) { if (order.orderName == null) return true; } filterOrder(product); // 这里会直接抛出类型错误!完全符合你的需求
原理是每个Symbol都是唯一的,TypeScript会严格检查这些专属属性,哪怕其他属性完全重合,也不会认为两个类型兼容。
方案2:使用字面量类型(更直观易读)
如果觉得Symbol有点晦涩,也可以给每个接口加一个明确的类型标识字段,比如:
interface Order { type: 'order'; // 固定的字面量类型,作为Order的专属标记 title?: string; orderName?: string; } interface Product { type: 'product'; title?: string; productId?: string; } var product: Product = { type: 'product' }; function filterOrder(order: Order) { if (order.orderName == null) return true; } filterOrder(product); // 直接报错,类型不兼容
这种方法不仅能解决类型兼容问题,还能让代码可读性更高,一眼就能区分不同的业务类型。
二、tsconfig配置强化检查
确保你的tsconfig.json里开启了严格模式,这能让TypeScript的类型检查更严格,提前发现这类潜在问题:
{ "compilerOptions": { "strict": true, // 开启所有严格类型检查选项 "strictFunctionTypes": true // 单独强化函数参数的类型检查,禁用双向协变 } }
不过要注意,仅靠tsconfig配置没法彻底解决你遇到的问题——因为结构类型系统的特性,只要两个类型有共同属性,还是会被认为兼容,所以必须结合上面的类型标记方案。
三、ESLint辅助规范
目前没有专门的ESLint规则能直接禁止这种无关类型兼容,但可以用以下规则辅助规范代码,减少这类问题的发生:
- 开启
@typescript-eslint/no-explicit-any:禁止使用any类型,避免类型检查被绕过 - 开启
@typescript-eslint/consistent-type-definitions:强制统一使用interface或type定义类型,让类型结构更清晰 - 开启
@typescript-eslint/explicit-function-return-type:强制函数声明返回类型,让类型检查更全面
最后解释下你遇到的奇怪现象:为什么注释掉Product.title就会报错?
因为TypeScript有个内置逻辑:如果两个类型没有任何共同属性,就会直接抛出“类型无共同属性”的错误;但只要有一个共同属性(哪怕是可选的),就会触发结构类型兼容判断,这就是为什么你去掉title?后反而报错的原因。
内容来源于stack exchange

