promise
UnwrapPromise, DeepAwaited, MaybePromise, PromiseAll, IsPromise.
import type {
UnwrapPromise, DeepAwaited,
MaybePromise, Promisable,
PromiseAll, IsPromise,
} from '@gentleduck/ttest/promise'
Promise-shape transforms. For async-aware function utilities (AsyncReturnType, Awaitable) see async; these helpers operate on plain Promise<T> shapes.
UnwrapPromise
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T
Unwrap Promise<T> to T; pass non-promises through unchanged.
type a = UnwrapPromise<Promise<number>> // number
type b = UnwrapPromise<string> // string
type c = UnwrapPromise<Promise<Promise<number>>> // Promise<number> (one level only)
Edge case: only one level is stripped. For full unwrapping use DeepAwaited.
DeepAwaited
type DeepAwaited<T> = T extends Promise<infer U> ? DeepAwaited<U> : T
Recursively unwrap nested promises.
type a = DeepAwaited<Promise<Promise<Promise<number>>>> // number
type b = DeepAwaited<Promise<string>> // string
type c = DeepAwaited<number> // number
Equivalent in behavior to the built-in Awaited<T> for Promise shapes; use it when you want the explicit name in your docs.
MaybePromise
type MaybePromise<T> = T | Promise<T>
T or a promise of T. Use for async-or-sync APIs that accept either.
function read<T>(getter: () => MaybePromise<T>): Promise<T> {
return Promise.resolve(getter())
}
read(() => 1) // ok — sync number
read(() => Promise.resolve('a')) // ok — async string
Promisable
type Promisable<T> = MaybePromise<T>
Alias of MaybePromise for type-fest parity.
PromiseAll
type PromiseAll<T extends readonly unknown[]> = { [K in keyof T]: Awaited<T[K]> }
Resolved tuple shape for Promise.all-style inputs. Maps each element through Awaited.
type a = PromiseAll<[Promise<1>, Promise<'a'>, 3]> // [1, 'a', 3]
type b = PromiseAll<readonly [Promise<number>, Promise<string>]> // readonly [number, string]
// Derive the resolved tuple for a known input.
async function all<T extends readonly unknown[]>(items: [...T]): Promise<PromiseAll<T>> {
return Promise.all(items) as Promise<PromiseAll<T>>
}
IsPromise
type IsPromise<T> = T extends Promise<unknown> ? true : false
true iff T is a Promise<unknown>.
import type { AssertTrue, AssertFalse } from '@gentleduck/ttest/assert'
type _ = [
AssertTrue <IsPromise<Promise<number>>>,
AssertFalse<IsPromise<number>>,
AssertFalse<IsPromise<{ then: (cb: () => void) => void }>>, // PromiseLike, not Promise
]
Edge case: IsPromise accepts Promise only, not PromiseLike. For thenables use IsPromiseLike.