FerJEP
FerJEP

Reputation: 33

Use a generic as a type without its type yet typescript

I've been the whole day trying to figure this out I could not.

I want to create a class that uses a generic type in its constructor without passing it the type yet:

//Tool.ts
export type ToolMethod<T> = (x: number, y: number, obj?: T) => void

export class Tool<T extends HTMLElement> {
  constructor(public element: T, public method: ToolMethod) {<-- /*Error here*/}
}

// or 

export class Tool<T extends HTMLElement, U extends ToolMethod> {
  constructor(public element: T, public method: U ){ /*Error ^ here too*/}
}

Because I want this:

//pencil.ts

const pencilElement = document.createElement('button')

const pencilMethod: ToolMethod<{/* some props */}> = (x,y, obj) => {
// ...
}

export const pencil = new Tool<HTMLButtonElement>(pencilElement, pencilMethod)

//or 

 export const pencil = new Tool<HTMLButtonElement, ToolMethod<{/*same props*/}>(pencilElement, pencilMethod)

I know that when I use a generic I have to pass a type, but I want to be able to specify that method has to be a ToolMethod without its type yet because the class still doesn't know it. Like as <T extends HTMLElement>, I'm able to select the specific element that tool will have, since not all elements share the same props.

Upvotes: 0

Views: 60

Answers (2)

jcalz
jcalz

Reputation: 330316

Your Tool class does need to be generic in two type parameters, but the second type parameter U doesn't need to be a ToolMethod itself; it could be the type parameter for ToolMethod:

export class Tool<T extends HTMLElement, U> {
  constructor(public element: T, public method: ToolMethod<U>) { }
}

Here, a Tool<T, U>'s method is a ToolMethod<U>. You can see it working:

const pencilMethod: ToolMethod<SomeProps> = (x, y, obj) => { }

export const pencil = new Tool(pencilElement, pencilMethod)
// const pencil: Tool<HTMLButtonElement, SomeProps>
pencil.element; // HTMLButtonElement
pencil.method; // ToolMethod<SomeProps>

Playground link to code

Upvotes: 4

I think You are looking for this:


// T is defined as function generic argument instead of type itself
export type ToolMethod = <T>(x: number, y: number, obj?: T) => void

export class Tool<T extends HTMLElement> {
  constructor(public element: T, public method: ToolMethod) { // no error here anymore

  }
}

You can define generic argument directly for function.

Upvotes: 0

Related Questions