Let's dive into less frequent Typescript feature - function overloading with a realistic example.
Have a custom hook
export function useUrlState( defaultState: T, searchParams?: object, )
At some moment I need to add more arguments to it, possibly more in the future. Hard to remember what Nth argument is, and calling a function like useUrlState(firstArg, null, null, fourthArg) is ridiculous. It will be way easier to pass arguments inside an object like this:
export function useUrlState({ defaultState, searchParams, replace }: { defaultState: T, searchParams?: object, replace?: boolean })
I will convert the function to a new format and keep it backward compatible with the existing implementation.
First, need to add overload signatures right above function implementation. Overload signatures are all possible ways a function can be called, with different argument's type and quantity.
/** * @deprecated Pass arguments in a object `useUrlState({ defaultState: form, searchParams })` * * * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#api} */ export function useUrlState(defaultState: T, searchParams?: object): { state: DeepReadonly , updateState: (value: Partial >, updateUrl: (value?: Partial >) => void, getState: () => DeepReadonly } /** * NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions * * @param {JSONCompatible } [defaultState] Fallback (default) values for state * @param {?SearchParams } [searchParams] searchParams from Next server component */ export function useUrlState ({ defaultState, searchParams }: { defaultState: T, searchParams?: object, replace?: boolean }): { state: DeepReadonly , updateState: (value: Partial >) => void, updateUrl: (value?: Partial >) => void, getState: () => DeepReadonly } // ( defaultState: T | { defaultState: T, searchParams?: object, replace?: boolean }, searchParams?: object, ) {
Tricky part is that signatures should be compatible with implementation, so have this defaultState: T | { defaultState: T, searchParams?: object, replace?: boolean }
I assume that if the first argument has a specific key, it is a new object format.
const _defaultState = ('defaultState' in defaultState ? defaultState.defaultState : defaultState) as T const _searchParams = ('defaultState' in defaultState ? defaultState.searchParams : searchParams) as object | undefined const _replace = ('defaultState' in defaultState ? defaultState.replace ?? true : false) as boolean
Also, can notice that replace argument has default value true for a new format, but for old one it's false.
Let's see how it works.
Notice that we have different JSDoc comments for each signature, old one marked with @deprecated tag.
Official docs https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads
Tnx for reading :)
Leave a comment about your experience, or if you have ideas how to do it more elegantly.
Disclaimer: All resources provided are partly from the Internet. If there is any infringement of your copyright or other rights and interests, please explain the detailed reasons and provide proof of copyright or rights and interests and then send it to the email: [email protected] We will handle it for you as soon as possible.
Copyright© 2022 湘ICP备2022001581号-3