Home > other >  How to express idempotent (self flatten) types in TypeScript?
How to express idempotent (self flatten) types in TypeScript?

Time:11-06

There are types with self flattening nature that is called Idempotence:

enter image description here

https://en.wikipedia.org/wiki/Idempotence

Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.

In JavaScript/TypeScript, we have Object/Number object for instance of idempotence.

A real world use-case is to write your own Promises with proper type in TypeScript. You can never have Promise<Promise<T>> only ever Promise<T> since promises auto-flatten. The same can happen with monads, for example.

console.log(
 Number(5) === Number(Number(5))
); // true
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

In a concise way, it's often expressed like

TTX = TX

I somehow managed to write in function

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

A extends T<X> ? A : //... works in the context of inside of some functions, but I don't know how to write the type itself alone, and even with function structure, it's very complicated, and I feel something is very wrong.

What I want to know and write is a definition of the idempotent type in TypeScript

type T<X> = ???
//where
T<T<X>> === T<X>

CodePudding user response:

You could write an idempotent wrapper around some inner type:

// just for reference, more practically this could be Promise<T>
type InnerType<T> = [T];
type IdempotentWrapper<X> = X extends InnerType<unknown> ? X : InnerType<X>;

type Foo = IdempotentWrapper<number>; // equivalent to InnerType<number>
type Bar = IdempotentWrapper<IdempotentWrapper<number>>; // equivalent to InnerType<number> as well
  • Related