0

I have created in typescript this wrapper for document.querySelector():

function qs(selector: string) {
  const elm = document.querySelector(selector)
  if (!elm) throw new Error(`'${sel}' is not in dom`)
  return elm
}

const canvas = qs('canvas')

canvas.getContext('2d')

Of course I get error TS2339: Property 'getContext' does not exist on type 'Element' on last line

Is there a way to make qr() return type depends of the selector argument like querySelector() does?

I tried this:

function qs<T extends Parameters<typeof document.querySelector>[0]>(
  selector: T
): ReturnType<typeof document.querySelector<typeof selector>> {
  return document.querySelector(selector)
}

But I get these errors:

error TS2344 Type 'T' does not satisfy the constraint 'Element'.
error TS2344 Type 'T' does not satisfy the constraint 'HTMLElementTagNameMap'.
error TS2344 Type 'T' does not satisfy the constraint 'SVGElementTagNameMap'.

In others words, I want the variable canvas to be of type HTMLCanvasElement without to have to do:

const canvas = qs('canvas') as HTMLCanvasElement

1 Answer 1

1

It's pretty hard (if not impossible to do feasibly?) to change the return type of querySelector so that it doesn't return null because it has overloads... so here's my workaround:

type Qs = {
    <K extends keyof HTMLElementTagNameMap>(selectors: K): HTMLElementTagNameMap[K];
    <K extends keyof SVGElementTagNameMap>(selectors: K): SVGElementTagNameMap[K];
    <E extends Element = Element>(selectors: string): E;
};

const qs: Qs = (selector: string) => {
  const elm = document.querySelector(selector)
  if (!elm) throw new Error(`'${selector}' is not in dom`);
  return elm
}

which is literally copying the type of querySelector but removing null from the return type.

Playground

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! it works perfectly! but Im' not sure to understand the first declaration. Is this an object declaration? (type Qs = { … })
@Yukulélé Yes, it's an object type with call signatures. See typescriptlang.org/docs/handbook/2/…
thank you so much for that perfect answer! You should probably be able to help me with step 2 of this question stackoverflow.com/questions/74204652/… 😇

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.