I'm trying to define a method that operates as a getter, taking an optional parameter. The getter provides access to an object of type T, and should return either the entire object, or a property on that object.
The challenge is that I am trying to defined the method in two places, first in an interface, and second in the actual implementation.
Here's my approach:
// Getter defines both overloads
interface StoreGetter {
<T>(): T;
<T, K extends keyof T>(prop: K): T[K];
}
// Store has a generic type, and exposes that type and properties on that type
interface Store<T> {
get: StoreGetter;
// Either one works individually
// get: <T>() => T;
// get: <T, K extends keyof T>(prop: K) => T[K];
}
export function makeStore<T>(initial: T): Store<T> {
let value: T = initial;
// Apparently, you can only define overloads via a function declaration
// function get<T>(): T;
// function get<T, K extends keyof T>(prop: K): T[K];
function get(prop?: keyof T) {
if (typeof prop !== 'undefined') {
return value[prop];
}
return value;
}
return {
get,
};
}
const store = makeStore({
text: '',
items: [],
num: 1
});
// Argument of type '"text"' is not assignable to parameter of type 'never'.(2345):
store.get('text')
// Object is of type 'unknown'.(2571)
store.get().
Unfortunately, the two definitions seem to clobber each other.
How can I define this method with overloads, and have correct type inference for both calls?


