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

如何在TypeScript中定义满足自展平特性的幂等(Idempotent)类型?

幂等类型定义与TypeScript实现问题

具有自展平特性的类型被称为幂等类型(Idempotence):

幂等性(Idempotence)是数学和计算机科学中部分运算的特性,指多次执行该运算的结果和首次执行的结果完全一致。

在JavaScript/TypeScript中,Object/Number对象就是幂等性的实例。

实际使用场景比如在TypeScript中为自定义Promise编写正确类型:由于Promise会自动展平,永远不会出现Promise<Promise<T>>类型,只会存在Promise<T>,monad也有类似特性。

示例代码:

console.log(
 Number(5) === Number(Number(5))
); // true

幂等性可简写为如下公式:
TTX = TX

概念区分说明

  • 幂等类型不会产生超出T的额外结构,对应JS数组形式就是[foo];而Haskell中monad的bind操作虽然也满足TTX = TX,但会保留[[foo]]这类嵌套结构。
  • Array.map组合运算会将[[foo]]转换为[[[foo]]]
  • Array.flatMap是map+flat的组合,满足TTX=TX规则,会将[[foo]]转换为[[foo]]

我认为Array.flatMap这类实现属于monad但不属于幂等,二者确实容易混淆。

已有的尝试

我尝试在函数中实现相关逻辑:

const toObject = <A, X>(x: A): A extends T<X> ? A : //...
        ((X:object)=> {/* ... */})(Object(x)) ;

A extends T<X> ? A : //...的逻辑在函数内部上下文可以运行,但我不知道如何单独定义该类型,就算用函数结构实现也非常复杂,我觉得实现思路存在问题。

核心问题

我想知道如何在TypeScript中定义幂等类型,满足如下规则:

type T<X> = ???
// 满足如下条件
T<T<X>> === T<X>

解决方案

核心实现思路是通过条件类型预判入参是否已经是目标包裹类型,如果是则直接返回自身,否则返回包裹后的类型,以下是不同场景的实现示例:

1. 通用幂等类型模板

// 通用幂等类型工厂:Wrapper为你要定义的目标包裹类型
type Idempotent<Wrapper, T> = T extends Wrapper ? T : Wrapper;

// 示例:幂等Number类型
type IdempotentNumber<T> = Idempotent<Number, T>;
// 验证规则
type TestN1 = IdempotentNumber<number>; // Number
type TestN2 = IdempotentNumber<TestN1>; // Number,完全符合TTX=TX要求

2. 自动展平的幂等Promise类型

// 递归处理多层嵌套的Promise,实现自动展平
type IdempotentPromise<T> = T extends Promise<infer U> ? IdempotentPromise<U> : Promise<T>;

// 验证规则
type TestP1 = IdempotentPromise<Promise<Promise<number>>>; // Promise<number>
type TestP2 = IdempotentPromise<TestP1>; // Promise<number>,满足要求

3. 幂等对象类型实现

type IdempotentObject<T> = T extends object ? T : object;

// 验证规则
type TestO1 = IdempotentObject<string>; // object
type TestO2 = IdempotentObject<TestO1>; // object,符合幂等规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 04:15:01