To simplify the typing process and ensure correct types are obtained when the function is used, I am working on creating functions with minimal explicit typing at the point of use. The function structure is shown below, where the type of the arg
in the callback function should depend on the string passed as the fntype
argument.
fn(fntype: string, callback: (arg: any) => void): void;
For instance,
fn('foo', (foo) => {
foo.somethingInTheFooInterface;
}
fn('bar', (bar) => {
bar.somethingInTheBarInterface;
}
Here are the types that have been established:
type FooType = "FooType";
const FooType: FooType = 'FooType';
type BarType = 'BarType';
const BarType: BarType = 'BarType';
type ActionTypes = FooType | BarType;
interface Action<T> {
type: T;
}
interface FooInterface extends Action<FooType> {
somethingOnTheFooInterface: string;
}
interface BarInterface extends Action<BarType> {
somethingOnTheBarInterface: string;
}
type CallbackTypes = FooInterface | BarInterface;
type Callback<T extends CallbackTypes> = (action: T) => void;
function fn<T extends CallbackTypes, U extends ActionTypes>(actionType: U, cb: Callback<T>): void;
function fn (actionType, cb) {
cb();
}
While these types work effectively when explicitly utilized:
// Works fine if we explicitly type the arg
fn(FooType, (arg: FooInterface) => {
arg.somethingOnTheFooInterface
});
// Works fine if we define the generics when calling
fn<FooInterface, FooType>(FooType, arg => {
arg.somethingOnTheFooInterface;
});
Unfortunately, the callback is not typed based on the first argument:
// TypeError as arg is typed as the union type CallbackTypes
fn(FooType, arg => {
arg.somethingOnTheFooInterface
})
If you have any suggestions or guidance on how to achieve this desired typing behavior, your input would be greatly appreciated.