I have a React hook that requests a remote API and returns something. By default, while the API is being fetch, the returned value is undefined
.
Still, I introduced a new prop that allows returning a default value – so, while the API is fetch, the default value is returned.
Is it possible for TypeScript to infer that when defaultValue
is defined, then the return can not be undefined
?
This is my code so far:
<code>interface UseMyHookOptions<T> {
defaultValue?: T
}
type UseMyHookReturn<T> = T extends undefined
? [T | undefined, (data: T) => void]
: [T, (data: T) => void]
function useMyHook<T>(key: string, options: UseMyHookOptions<T> = {}): UseMyHookReturn<T>{
const defaultValue = options?.defaultValue
const remoteValue = useFetch<T>(`/api/${key}`)
const setValue = (value: T) => { console.log(value) }
const value = remoteValue ?? defaultValue;
return [value, setValue] as UseMyHookReturn<T>;
}
</code>
<code>interface UseMyHookOptions<T> {
defaultValue?: T
}
type UseMyHookReturn<T> = T extends undefined
? [T | undefined, (data: T) => void]
: [T, (data: T) => void]
function useMyHook<T>(key: string, options: UseMyHookOptions<T> = {}): UseMyHookReturn<T>{
const defaultValue = options?.defaultValue
const remoteValue = useFetch<T>(`/api/${key}`)
const setValue = (value: T) => { console.log(value) }
const value = remoteValue ?? defaultValue;
return [value, setValue] as UseMyHookReturn<T>;
}
</code>
interface UseMyHookOptions<T> {
defaultValue?: T
}
type UseMyHookReturn<T> = T extends undefined
? [T | undefined, (data: T) => void]
: [T, (data: T) => void]
function useMyHook<T>(key: string, options: UseMyHookOptions<T> = {}): UseMyHookReturn<T>{
const defaultValue = options?.defaultValue
const remoteValue = useFetch<T>(`/api/${key}`)
const setValue = (value: T) => { console.log(value) }
const value = remoteValue ?? defaultValue;
return [value, setValue] as UseMyHookReturn<T>;
}
Expected examples:
<code>// `foo` type: expected: T (because defaultValue is defined)
// got: T
const [foo, setFoo] = useMyHook<string>('foo', { defaultValue: 'something' });
// `bar` type: expected: T | undefined (because defaultValue is not defined)
// got: T
const [bar, setBar] = useMyHook<string>('bar');
</code>
<code>// `foo` type: expected: T (because defaultValue is defined)
// got: T
const [foo, setFoo] = useMyHook<string>('foo', { defaultValue: 'something' });
// `bar` type: expected: T | undefined (because defaultValue is not defined)
// got: T
const [bar, setBar] = useMyHook<string>('bar');
</code>
// `foo` type: expected: T (because defaultValue is defined)
// got: T
const [foo, setFoo] = useMyHook<string>('foo', { defaultValue: 'something' });
// `bar` type: expected: T | undefined (because defaultValue is not defined)
// got: T
const [bar, setBar] = useMyHook<string>('bar');
Playground