Dart泛型扩展方法优化:实现超类型兼容并保留类型推断
实现支持超类型返回且保留类型推断的When扩展
核心需求是要一个通用的when扩展方法,既能在满足条件时返回原对象,不满足时返回其超类型对象,同时保留Dart的类型推断能力,不用为每个特定类型(比如Widget)单独写扩展。
原方案的问题
- 第一个泛型扩展仅能返回原类型
T,用在Widget场景时需要手动强制转换,操作繁琐; - 针对Widget编写的特定扩展虽解决了转换问题,但需要为每个需求类型重复编写,扩展性差;
- 尝试的双泛型
<R extends Object, T extends R>扩展会丢失类型推断,导致返回值默认是Object,无法调用子类方法,存在类型安全隐患。
解决方案:调整泛型参数设计
以下扩展方法可完美解决问题,既支持超类型返回,又能保留完整的类型推断:
extension When<T extends Object> on T { R? when<R>( bool Function(T self) predicate, { R Function(T self)? otherwise, }) { if (predicate(this)) { // 满足条件时返回原对象,T必然是R的子类型(由类型推断保证) return this as R; } return otherwise?.call(this); } }
效果验证
用你给出的测试代码验证:
final variable = 1.when((self) => self.isEven, otherwise: (self) => self + 0.5)!;
此时variable的类型会被自动推断为num(int和double的最小上界),可直接调用num的所有方法(比如toInt()),不会出现类型安全警告。
再看Widget场景的使用示例:
Widget build(BuildContext context) { return const Text("Hello").when( (self) => self.data == "Hello", otherwise: (self) => const Icon(Icons.error), )!; }
这里返回值会被推断为Widget,不需要任何强制转换,编译器会自动识别。
方案可行原因
- 泛型参数
R由调用上下文自动推断:Dart会根据otherwise的返回类型和原对象T的类型,自动计算出两者的最小上界作为R的类型; - 无需重复编写特定类型扩展:无论用在
int、Widget还是其他类型上,这个单一扩展都能处理; - 类型安全有保障:只要
otherwise返回的是T的超类型,this as R的转换就不会出错,编译器也会在编译阶段进行类型检查。
内容的提问来源于stack exchange,提问作者FMorschel
相关产品推荐
相关产品推荐

