diff --git a/src/core/atom.ts b/src/core/atom.ts index 6fd8fecdfa..106f79897c 100644 --- a/src/core/atom.ts +++ b/src/core/atom.ts @@ -1,4 +1,10 @@ -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable interface Getter { (atom: Atom>): Value diff --git a/src/core/store.ts b/src/core/store.ts index 8889783314..87a5b362bd 100644 --- a/src/core/store.ts +++ b/src/core/store.ts @@ -8,7 +8,13 @@ import { } from './suspensePromise' import type { SuspensePromise } from './suspensePromise' -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable type AnyAtomValue = unknown type AnyAtom = Atom diff --git a/src/core/useAtom.ts b/src/core/useAtom.ts index c3c33cba5e..2c01204ebf 100644 --- a/src/core/useAtom.ts +++ b/src/core/useAtom.ts @@ -2,7 +2,13 @@ import type { Atom, Scope, SetAtom, WritableAtom } from './atom' import { useAtomValue } from './useAtomValue' import { useSetAtom } from './useSetAtom' -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable export function useAtom>( atom: WritableAtom, diff --git a/src/core/useAtomValue.ts b/src/core/useAtomValue.ts index 32d76ab327..612b4e89c0 100644 --- a/src/core/useAtomValue.ts +++ b/src/core/useAtomValue.ts @@ -11,7 +11,13 @@ import { getScopeContext } from './contexts' import { COMMIT_ATOM, READ_ATOM, SUBSCRIBE_ATOM } from './store' import type { VersionObject } from './store' -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable export function useAtomValue( atom: Atom, diff --git a/src/utils/loadable.ts b/src/utils/loadable.ts index 494b874e0d..abb8b40cc3 100644 --- a/src/utils/loadable.ts +++ b/src/utils/loadable.ts @@ -2,7 +2,13 @@ import { atom } from 'jotai' import type { Atom } from 'jotai' import { createMemoizeAtom } from './weakCache' -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable const memoizeAtom = createMemoizeAtom() diff --git a/src/utils/selectAtom.ts b/src/utils/selectAtom.ts index c393bfc308..e469a473e5 100644 --- a/src/utils/selectAtom.ts +++ b/src/utils/selectAtom.ts @@ -2,7 +2,13 @@ import { atom } from 'jotai' import type { Atom } from 'jotai' import { createMemoizeAtom } from './weakCache' -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable const memoizeAtom = createMemoizeAtom() diff --git a/src/utils/waitForAll.ts b/src/utils/waitForAll.ts index b360b78bf5..3567ca7218 100644 --- a/src/utils/waitForAll.ts +++ b/src/utils/waitForAll.ts @@ -5,7 +5,13 @@ import { createMemoizeAtom } from './weakCache' const memoizeAtom = createMemoizeAtom() const emptyArrayAtom = atom(() => []) -type Awaited = T extends Promise ? Awaited : T +type Awaited = + T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode + T extends object & { then(onfulfilled: infer F): any } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped + F extends ((value: infer V, ...args: any) => any) ? // if the argument to `then` is callable, extracts the first argument + Awaited : // recursively unwrap the value + never : // the argument to `then` was not callable + T; // non-object or non-thenable type ResolveAtom = T extends Atom ? V : T type AwaitedAtom = Awaited>