我正在尝试键入一些函数以在使用函数时获取正确的类型,并且在此使用点上显式键入最少。本质上该函数如下,我的目标是根据作为arg
参数传递的字符串键入回调函数的fntype
。
fn(fntype: string, callback: (arg: any) => void): void;
例如,
fn('foo', (foo) => {
foo.somethingInTheFooInterface;
}
fn('bar', (bar) => {
bar.somethingInTheBarInterface;
}
这些是我提出的类型:
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();
}
明确使用内容时哪种方法可以正常工作:
// 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;
});
但是没有根据第一个参数键入回调:
// TypeError as arg is typed as the union type CallbackTypes
fn(FooType, arg => {
arg.somethingOnTheFooInterface
})
如果有人可以就如何实现这种打字提供任何指导,那么我将非常感激。
答案 0 :(得分:1)
如果我理解正确,那么这似乎是一种重大的矫枉过正 您应该能够通过签名重载实现目标:
interface FooInterface {
somethingOnTheFooInterface: string;
}
interface BarInterface {
somethingOnTheBarInterface: string;
}
fn(fntype: "FooType", callback: (arg: FooInterface) => void): void;
fn(fntype: "BarType", callback: (arg: BarInterface) => void): void;
fn(type: string, callback: (arg: any) => void) { ... }
答案 1 :(得分:0)
从Typescript 2.9开始,在没有函数重载的情况下,可以使用条件类型:
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<T> =
T extends FooType ? FooInterface :
T extends BarType ? BarInterface :
never;
type Callback<T> = (action: T) => void;
function fn<T extends ActionTypes, U extends CallbackTypes<T>>(actionType: T, cb: Callback<U>) {
cb({} as any);
};
fn(FooType, arg => {
arg.somethingOnTheFooInterface
})
fn(BarType, arg => {
arg.somethingOnTheBarInterface
})