I am attempting to create an overloaded function that will write to and from session storage instead of the standard state. I'd like it to be overloadable in the instances where I only provide a type and not an initial value. Exactly like what useState
does in react.
Here is what I have so far:
export function useSessionState<S = undefined>(initialState?: S): [S, (state: S) => void];
export function useSessionState<S>(initialState: S): [S, (state: S) => void] {
const [state, setState] = useState<S>()
// Unimportant: Do something to load to and from session storage.
return [state, (value) => {
}]
}
When I try to consume this type I only ever get the result type of one of the overloads.
// Variable 'state' is a string as expected.
const [state, setState] = useSessionState("some_initial_value")
// Variable 'undefinedState' is also a string, but it should be undefined since no 'initialState' was provided.
const [undefinedState, setUndefinedState] = useSessionState<string>()
I didn't know the answer myself, so I started reading and experimenting. My attempts come pretty close, but I see the following flaws:
initialState
as being of type S
instead of S | undefined
S | undefined
, which means you'd strugle to implement this function without a cast. .d.ts
of the first solution and the second solution are different. I believe the .d.ts
of the first attempt more closely resembles the official useState
definition.initialState
can be a value or a function, which is only the case in the second attempt. setState
function should probably have a parameter of type S | undefined
S | undefined
, rather than S
. Hopefully there is a better solution... If only the actual implementation was written in Typescript.
function useState<S>(initialState: S): [S, (state: S) => void];
function useState<S = undefined>(): [S | undefined, (state: S) => void];
function useState<S = undefined>(initialState?: S): [S extends undefined ? undefined | S : S, (state: S) => void] {
throw new Error(`Not implemented and not using ${initialState}`);
}
const [state1, setState1] = useState<string>("initialValue"); // string
const [state2, setState2] = useState("initialValue"); // string
const [state3, setState3] = useState<string>(); // undefined | string
const [state4, setState4] = useState(); // undefined
The .d.ts
that is generated on the playground:
declare function useState<S>(initialState: S): [S, (state: S) => void];
declare function useState<S = undefined>(): [S | undefined, (state: S) => void];
type Dispatch<T> = (value: T) => void;
function useState<S = undefined>(): [S | undefined, Dispatch<S | undefined>];
function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>];
function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>] {
throw new Error(`Not implemented and not using ${initialState}`);
}
const [state1, setState1] = useState<string>("initialValue"); // string
const [state2, setState2] = useState("initialValue"); // string
const [state3, setState3] = useState<string>(); // undefined | string
const [state4, setState4] = useState(); // undefined
The .d.ts
that is generated on the playground:
declare function useState<S = undefined>(): [S | undefined, Dispatch<S | undefined>];
declare function useState<S>(initialState?: S | (() => S)): [S, Dispatch<S>];
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.