TypeScript联合返回类型的Java替代方案及实现问题咨询
解决Java实现neverthrow Result时Err.andThen的类型兼容问题
核心问题分析
TypeScript的联合类型E | F在Java中没有直接等价物,且Java泛型是不变的——Err<T, E>无法直接赋值给Result<U, E | F>(甚至没有E | F这种类型)。而neverthrow中Err的andThen逻辑是直接返回自身,这就需要在Java中通过泛型约束和安全的类型转换来适配。
可行解决方案
1. 重构Result接口与Err类
首先,Err状态下不会访问value,因此可以去掉Err类中不必要的T泛型,简化类型结构:
import java.util.function.Function; // 定义基础Result接口 public interface Result<T, E> { // 引入泛型G作为返回结果的错误超类型,兼容原错误E和新错误F <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn); } // Ok类:持有有效结果,正常执行andThen逻辑 public class Ok<T, E> implements Result<T, E> { private final T value; public Ok(T value) { this.value = value; } @Override public <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn) { return fn.apply(value); } } // Err类:去掉T泛型,因为Err状态下不会使用value public class Err<E> implements Result<Object, E> { private final E error; public Err(E error) { this.error = error; } @SuppressWarnings("unchecked") @Override public <U, G> Result<U, G> andThen(Function<Object, Result<U, ? extends G>> fn) { // 安全转换:Err状态下不会触发fn,value类型不影响;E必然是G的子类型(编译器自动推断G为E和F的共同超类型) return (Result<U, G>) this; } }
2. 类型适配逻辑说明
- 泛型参数G:编译器会自动推断
G为原错误类型E和fn返回的错误类型F的最小共同超类型(比如E=IOException、F=SQLException时,G=Exception)。 - Err的类型转换:由于Err状态下不会执行
andThen传入的函数,返回的Err实例的value类型(Object)不会被访问,因此强制转换为Result<U, G>是安全的。 - 兼容性保证:Ok类执行
fn后返回的Result<U, F>,因F extends G,自然符合Result<U, G>的类型要求;Err类转换后的实例也符合该类型,完美匹配方法返回值。
3. 使用示例
public class Main { public static void main(String[] args) { // Ok状态:执行andThen转换类型 Result<String, IOException> okResult = new Ok<>("test"); Result<Integer, Exception> intResult = okResult.andThen(s -> new Ok<>(s.length()) ); // Err状态:直接返回自身,类型自动适配 Result<String, IOException> errResult = new Err<>(new IOException("error")); Result<Integer, Exception> errIntResult = errResult.andThen(s -> new Ok<>(s.length()) ); } }
替代方案:保留Err的T泛型
如果需要保留Err的T泛型(比如某些场景下需要访问Err的value),可以通过通配符和类型转换实现:
public class Err<T, E> implements Result<T, E> { private final T value; private final E error; public Err(T value, E error) { this.value = value; this.error = error; } @SuppressWarnings("unchecked") @Override public <U, G> Result<U, G> andThen(Function<T, Result<U, ? extends G>> fn) { return (Result<U, G>) this; } }
这种方式本质和之前一致,只是保留了T泛型,转换逻辑同样安全——因为Err状态下不会触发fn,也不会被当作Ok状态访问U类型的value。
内容的提问来源于stack exchange,提问作者Dmitry Zlykh
相关产品推荐
相关产品推荐

