如何在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
相关产品推荐
相关产品推荐

