In my code, I have a custom utility function that wraps document.querySelector
function querySelector<T extends HTMLElement>(selector: string) {
return document.querySelector<T>(selector);
}
I modified it to include an option to throw an error if the specified element is not found.
function querySelector<T extends HTMLElement>(
selector: string,
options: {
required?: boolean
} = {}
) {
const element = document.querySelector<T>(selector);
if (options.required && !element) {
throw new ReferenceError(`Can't find an element that matches "${selector}"`);
}
return element;
}
The issue I'm encountering is that document.querySelector
can return either the element or null
, leading TypeScript to infer the return type of my querySelector
function as T | null
(since without the requirement specification, that's the most logical assumption).
const foo = querySelector(".foo", { required: true });
foo.addEventListener("abc", () => {});
// ts(18047) 'foo' is possibly 'null'
After reading a discussion on Reddit, it seems feasible to adjust the return type of my function based on the parameters, but I'm struggling to implement this when checking the object parameter property.
My initial approach was to introduce another parameter within the angle brackets, but this didn't yield any positive results.
type QuerySelectorOptions = Partial<{
required: boolean
}>;
function querySelector<T extends HTMLElement, O extends QuerySelectorOptions>(
selector: string,
options: O = {}
// ts(2322) "... could be instantiated with a different subtype ..."
) {
// ...
}
I'm finding it challenging to access options
without specifying it as O
.
function querySelector<T extends HTMLElement>(
selector: string,
options: QuerySelectorOptions = {}
): options.required /* ... */ { // ts(2503) Cannot find namespace 'options'
// ...
}
Is there a way to adjust the return type of my function based on the property of one of the parameters, or am I facing an impossible/impractical task?