Issue
I am building some helper classes that operate on or get some specific DOM element types.
So I have for example an HTMLDivElementHelper all public methods should return HTMLDivElement.
Those methods contain at least one params but they can also contain 2.
I am trying to force this with an interface or similar but I can not find how to do it.
If I use class MyHelper implements Record<string, () => HTMLDivElement> Typescript complains that Property 'setValue' of type '(selector: string) => HTMLDivElement' is not assignable to 'string' index type '() => HTMLDivElement'.(2411)
Is this possible?
Solution
If you'd like to allow your class to have members that aren't functions, then you can't use a string index signature, nor can you say implements Record<string, XXX> because the Record<K, V> utility type is the same as an index signature when your key type is string.
Instead, you can come up with a generic type CheckMethods<T> that acts as a constraint on your class. The idea is that you write class MyHelper implements CheckMethods<MyHelper> { /* ... */ }, where CheckMethods<MyHelper> will evaluate to something compatible with MyHelper if and only if all the methods (well, function-valued members) are of the type you want them to be. This sort of self-referential constraint is known as "F-bounded quantification". Here's a possible implementation:
type CheckMethods<T> = { [K in keyof T]: T[K] extends Function ?
((selector: string, options: any) => HTMLDivElement) : T[K] }
Here CheckMethods<T> is a mapped type where each property key K from T is mapped to a new property type. The old property type T[K] is checked with a conditional type to see if it's a Function or not. If it's not, we just map it to itself, T[K], which will always be true. If it is a function, then we map it to a specific function type (selector: string, options: any) => HTMLDivElement, which will work with any function of up to two parameters of the same type (see the documentation for function compatiblity for more information.
Let's see it in action:
class MyHelper implements CheckMethods<MyHelper> {
nonMethod = 123; // okay
setValue(selector: string): HTMLDivElement { // okay
return document.createElement('div');
}
setTest(selector: string, options: { options: string }): HTMLDivElement { // okay
return document.createElement('div');
}
badParameter(selector: number): HTMLDivElement { // error!
return document.createElement("div");
}
badReturn(selector: string) { return 3 } // error!
}
Looks good!
Answered By - jcalz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.