I have created a unique TypeScript type called Awaitable<T>
with the goal of ensuring that
Awaited<Awaitable<T>>
is always equal to T
.
export type Awaitable<T> =
| (T extends Record<'then', Function> ? never : T)
| PromiseLike<T>;
While working on some code, I encountered a puzzling type error where a certain comparison was expected to be false according to TypeScript, but it actually turned out to be true at runtime.
(async () => {
const something = {
then: <T>(callback: (value: { data: false }) => PromiseLike<T>) => callback({ data: false }),
data: true,
} as const satisfies PromiseLike<{ data: false }> & { data: true };
const typed: Awaitable<{ data: true }> = something;
const awaited = await typed;
if (awaited.data === false) { // This comparison seems unintentional due to incompatible types 'true' and 'false'. (2367)
console.log("so, this would never printed. right?");
}
})();
How can we bridge the gap between TypeScript's static type system and the actual behavior at runtime?
I'm currently stuck and struggling to find a solution for this dilemma. Any ideas or suggestions are greatly appreciated!
Edit
The root issue lies in the fact that the function below may return a value that contradicts its specified type.
async function AcceptsAwaitable<T>(awaitable: Awaitable<T>): Promise<T> {
return await awaitable;
}