如何使用不同的回调重载参数干净地编写TypeScript函数
这是 鉴于此代码:如何使用不同的回调重载参数干净地编写TypeScript函数,typescript,typescript2.4,Typescript,Typescript2.4,这是 鉴于此代码: 类动物{ a:弦; } 狗类动物{ b:弦; } 类Foo{} 功能测试(动物:A,func:(p:A)=>T):T; 功能测试(动物:A,func:(p:A)=>Foo):Foo; 功能测试(动物:A,功能:(p:A)=>T | Foo:T | Foo{ 返回函数(动物); } 是否有一种更干净的方式来编写不需要a类型参数的重载?或者是一个写这些东西的清洁工?基本上,函数使用给定的animal有条件地调用给定的func。如果给狗,则返回类型T。如果给予其他动物,则返回类型
类动物{
a:弦;
}
狗类动物{
b:弦;
}
类Foo{}
功能测试(动物:A,func:(p:A)=>T):T;
功能测试(动物:A,func:(p:A)=>Foo):Foo;
功能测试(动物:A,功能:(p:A)=>T | Foo:T | Foo{
返回函数(动物);
}
是否有一种更干净的方式来编写不需要a类型参数的重载?或者是一个写这些东西的清洁工?基本上,函数使用给定的animal
有条件地调用给定的func
。如果给狗,则返回类型T
。如果给予其他动物,则返回类型Foo
更新1
我无法让@jcalz版本正常工作,但我花了一段时间才意识到它与承诺有关,但我不确定如何解决这个问题。以下是我的“丑陋但有效”的方法论和@jalz的“很好,但已经破产”的方法论:
类动物{
a:弦;
}
狗类动物{
b:弦;
}
类Foo{}
功能测试(动物:A,func:(p:A)=>Promise):Promise;
功能测试(动物:A,func:(p:A)=>Promise):Promise;
功能测试(动物:A,func:(p:A)=>Promise | Promise):Promise{
返回函数(动物);
}
const-foo:Promise=test(new-Animal(),(a)=>{return-Promise.resolve(new-foo());});
const-other:Promise=test(newdog(),(d)=>{return-Promise.resolve(d.b);});
类型AnimalFunc={
(狗:狗):承诺;
(动物:动物):承诺;
}
功能测试2(dog:dog,func:AnimalFunc):承诺;
功能测试2(动物:动物,功能:动物基金):承诺;
功能测试2(动物:动物,功能:动物基金):承诺{
返回函数(动物);
}
const foo2:Promise=test2(新动物(),
(a) =>{
return Promise.resolve(new Foo());
}); // 错误:类型为“(a:any)=>Promise”的TS2345参数不能分配给类型为“AnimalFunc”的参数。
//类型“Promise”不可分配给类型“Promise”。
//类型“Foo”不可分配给类型“string”。类型脚本虚拟项目C:\\u Dev\CRM\WebResources\WebResources\new\uscripts\Payment.ts 498处于活动状态
constother2:Promise=test2(newdog(),(d)=>{returnpromise.resolve(d.b);});
我明白
函数使用给定的动物有条件地调用给定的func
。如果给狗,则返回类型T
。如果给予其他动物,则返回类型Foo
表示参数func
接受所有Animal
输入,但根据其输入是否为Dog
返回不同类型。这意味着我要将func
声明为以下重载类型:
type AnimalFunc<T> = {
(dog: Dog): T;
(animal: Animal): Foo<T>;
}
希望有帮助
更新1
@达里尔:
这适用于定义,但不适用于调用站点。如果我传入一个dog作为第一个参数,我的函数必须接受一个dog并返回一个T,否则它必须接受一个animal并返回一个Foo,在调用站点,它会抱怨函数没有返回其他类型(T或Foo)
如果不知道您的所有用例,我无法说出最好的定义是什么。如果您真的有一个AnimalFunc
类型的函数,它应该可以工作:
function func1(dog: Dog): string;
function func1(animal: Animal): Foo<string>;
function func1(animal: Animal): string | Foo<string> {
if (animal instanceof Dog) {
return "woof";
}
return new Foo<string>();
};
var dog: Dog = new Dog();
var cat: Animal = new Animal();
var dogTest: string = test(dog, func1);
var catTest: Foo<string> = test(cat, func1);
注意,test3
(前两行)的声明是为了调用方的利益而键入的,而实现(第三行)是为了实现者的利益而键入的。如果您所关心的只是调用test3
的人的类型安全,但是您的实现足够安全,您不需要TS为您验证类型,那么您可以将其实现为:
function test3<T>(dog: Dog, func: (dog: Dog) => Promise<T>): Promise<T>;
function test3<T>(animal: Animal, func: (animal: Animal) => Promise<Foo<T>>): Promise<Foo<T>>;
function test3(animal: any, func: any): any {
return func(animal); // fine, but even return animal(func) would be accepted here, to disastrous results at runtime
}
这将导致第一个重载声明出现问题,因为它永远不会返回承诺
我希望这有帮助 这适用于定义,但不适用于调用站点。如果我传入一只狗作为第一个参数,我的函数必须接受一只狗并返回一个T,否则它必须接受一只动物并返回一个Foo,在调用站点,它抱怨函数没有返回其他类型(T或Foo)啊,我实际上是在返回承诺,这对我来说是一团糟,但我不知道如何修复它。我更新了我的答案,用了一个有效的例子。太棒了。您基本上拥有我所拥有的,但我没有意识到您不必为重载定义泛型类型。这确实使它更简单。我要提出的另一个建议是使用Promise
vsPromise | Promise
function test3<T>(dog: Dog, func: (dog: Dog) => Promise<T>): Promise<T>;
function test3<T>(animal: Animal, func: (animal: Animal) => Promise<Foo<T>>): Promise<Foo<T>>;
function test3<T, A extends Animal>(animal: A, func: (animal: A) => Promise<T> | Promise<Foo<T>>): Promise<T> | Promise<Foo<T>> {
return func(animal);
}
function test3<T>(dog: Dog, func: (dog: Dog) => Promise<T>): Promise<T>;
function test3<T>(animal: Animal, func: (animal: Animal) => Promise<Foo<T>>): Promise<Foo<T>>;
function test3(animal: any, func: any): any {
return func(animal); // fine, but even return animal(func) would be accepted here, to disastrous results at runtime
}
function test3<T, A extends Animal>(animal: A, func: (animal: A) => Promise<T> | Promise<Foo<T>>): Promise<T> | Promise<Foo<T>> {
return Promise.resolve(new Foo<T>()); // no error!!
}