When dealing with legacy code that utilizes a const
in the following pattern:
const fnUsedInSetPrototypeOf = {
equalityComparer<T>(a: T, b: T) { return a === b },
otherFn<T> (this: T) { /*...*/ },
// ... other things, all along the lines of `method<T> (...)`
} as const
I am interested in merging the typeof fnUsedInSetPrototypeOf
into a generic interface that collapses all the functions to the generic type of the extending interface. For example:
type Proto = typeof fnUsedInSetPrototypeOf
interface SuperProto<T> extends Proto {
equalityComparer (a: T, b: T): boolean
}
This approach would streamline and expedite the process of adding types to an existing JavaScript codebase like Knockout/TKO.
However, I encountered this error:
Type
(a: T, b: T) => boolean
is not assignable to type.<T>(a: T, b: T) => boolean
Various attempts have been made to resolve this issue, such as defining mappings for types like:
type Proto<T> = { [key in keyof typeof fnUsedInSetPrototypeOf]: fnUsedInSetPrototypeOf<T>[key]?? }
, but no solution has proved effective so far.
The underlying challenge I am trying to address is somewhat more complex, involving multiple inheritances of fnUsedInSetPrototypeOf
and SuperProto<T>
, as seen in the Knockout Observable type within the Knockout/TKO library.
A Playground has been provided to showcase the problem, along with various attempted solutions to rectify it.
Edit:
In a second playground, the challenge persists:
const fnUsedInSetPrototypeOf = {
equalityComparer<T>(a: T, b: T) { return a === b },
otherFn<T> (this: SuperProto<T>, v: T) { /*...*/ },
otherFn2<T, U> (this: T, v: U) { /*...*/ },
} as const
type Proto = typeof fnUsedInSetPrototypeOf
interface SuperProto<T> extends Omit<Proto, keyof SuperProto<T>> {
equalityComparer (a: T, b: T): boolean
// equalityComparer<T> (a: T, b: T): boolean
}
// This should not give an error
const x = (v: SuperProto<number>) => v.otherFn(123)
const x2 = (v: SuperProto<number>) => v.otherFn2(123)
// This should error with argument to `otherFn` not being a number
const y = (v: SuperProto<number>) => v.otherFn('abc')
const y2 = (v: SuperProto<number>) => v.otherFn2('abc')