如何在TypeScript中实现类似Rust枚举、Kotlin密封类的变体类型
在TypeScript中创建类似Rust枚举/Kotlin密封类的HTTP响应变体类型
我希望在TypeScript中为HTTP响应创建一种可包含多种状态的变体类型。在Rust中可如下实现:
enum Response<T> { Empty, Loading, Failure(String), Success(data: T), }
在Kotlin中可通过密封类实现:
sealed class Response<out T> { object Empty: Response<Nothing>() object Loading: Response<Nothing>() class Failure(val err: String): Response<Nothing>() class Success(val data: T): Response<T>() }
请问在TypeScript中是否有办法创建这类变体类型?
答案:可以使用区分联合类型(Discriminated Unions)
TypeScript没有原生支持带关联数据的枚举,但可以通过区分联合类型实现相同效果——这是TS中处理多状态变体类型的标准方案,具备完整的类型安全性。
基础实现:带区分标记的联合类型
定义包含所有状态的联合类型,每个状态通过唯一的type字段作为区分符,同时携带对应的数据:
// 定义HTTP响应变体类型 type Response<T> = | { type: 'Empty' } | { type: 'Loading' } | { type: 'Failure'; error: string } | { type: 'Success'; data: T };
创建各状态实例
// 空状态 const emptyResp: Response<never> = { type: 'Empty' }; // 加载中状态 const loadingResp: Response<never> = { type: 'Loading' }; // 失败状态 const failureResp: Response<never> = { type: 'Failure', error: '请求超时,请重试' }; // 成功状态(携带自定义数据类型) const successResp: Response<{ id: number; name: string }> = { type: 'Success', data: { id: 1, name: '用户信息' } };
类型收窄与处理
TypeScript会根据type字段自动推断每个分支的具体类型,无需额外类型断言:
function handleResponse<T>(response: Response<T>) { switch (response.type) { case 'Empty': console.log('当前无响应数据'); break; case 'Loading': console.log('数据加载中...'); break; case 'Failure': // 此处response.error自动推断为string类型 console.error('请求失败:', response.error); break; case 'Success': // 此处response.data自动推断为T类型 console.log('请求成功,数据:', response.data); break; } }
可选:类风格实现(接近Kotlin密封类)
如果希望每个状态是类实例(更贴近Kotlin密封类的写法),可以用抽象类+内部子类实现:
abstract class Response<T> { private constructor() {} static Empty = class extends Response<never> {}; static Loading = class extends Response<never> {}; static Failure = class extends Response<never> { constructor(public error: string) { super(); } }; static Success = class<T> extends Response<T> { constructor(public data: T) { super(); } }; } // 使用示例 const empty = new Response.Empty(); const loading = new Response.Loading(); const failure = new Response.Failure('接口返回错误'); const success = new Response.Success({ id: 2, content: '文章内容' });
这种方式需要用instanceof进行类型收窄:
function handleResponse<T>(response: Response<T>) { if (response instanceof Response.Empty) { console.log('响应为空'); } else if (response instanceof Response.Loading) { console.log('加载中'); } else if (response instanceof Response.Failure) { console.error('失败原因:', response.error); } else if (response instanceof Response.Success) { console.log('获取数据:', response.data); } }
内容的提问来源于stack exchange,提问作者dessalines
相关产品推荐
相关产品推荐

