我试图在TypeScript中创建一个“汇总”服务,该服务可以根据对象的类型保存对象,但是TypeScript告诉我我在做非法的事情(TS2322
)。
这是我的代码的简化版本;首先,我有一个枚举,描述了我拥有的所有对象类:
enum ThingType {
SomeThing = 'SomeThing',
OtherThing = 'OtherThing',
}
然后有一个描述基本类型以及几个派生类型的接口:
interface IThing {
name: string;
type: ThingType;
}
interface ISomeThing extends IThing {
// properties of ISomeThing
}
interface IOtherThing extends IThing {
// properties of IOtherThing
}
对于每种派生类型,都有一种特定的服务可以保存这些类型的对象:
function saveSomeThing(someThing: ISomeThing): Promise<ISomeThing> {
return Promise.resolve(someThing);
}
function saveOtherThing(otherThing: IOtherThing): Promise<IOtherThing> {
return Promise.resolve(otherThing);
}
现在,我希望有一个“汇总”服务,将保存操作委派给正确的实现:
function saveThing<T extends IThing>(thing: T): Promise<T> {
switch (thing.type) {
case ThingType.SomeThing: return saveSomeThing(thing as ISomeThing);
case ThingType.OtherThing: return saveOtherThing(thing as IOtherThing);
default: throw new Error('Unknown type: ' + thing.type);
}
}
TypeScript告诉我我的return
语句无效:
TS2322: Type 'Promise<ISomeThing>' is not assignable to type 'Promise<T>'.
Type 'ISomeThing' is not assignable to type 'T'.
'ISomeThing' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'IThing'.
这很公平-TypeScript不知道T
的那个分支的ISomeThing
将是switch
-有没有办法我可以告诉TypeScript它是(没有求助于unknown
或any
)?
答案 0 :(得分:1)
有两种方法:
as any
标记返回(由于函数本身是键入的,因此不会丢失任何类型信息)在这里主要是因为另一种方式比较麻烦,并且不会增加任何实际价值:
function saveThing<T extends IThing>(thing: T): Promise<T> {
switch (thing.type) {
case ThingType.SomeThing: return saveSomeThing(thing as ISomeThing) as any;
case ThingType.OtherThing: return saveOtherThing(thing as IOtherThing) as any;
default: throw new Error('Unknown type: ' + thing.type);
}
}
function saveThing<T extends IThing>(thing: T): Promise<T extends ISomeThing ? ISomeThing : IOtherThing> {
type returnType = T extends ISomeThing ? ISomeThing : IOtherThing;
if(isISomeThing(thing)){
return saveSomeThing(thing) as Promise<returnType>;
}
if(isIOtherThing(thing)){
return saveOtherThing(thing) as Promise<returnType>;
}
throw new Error('Unknown type: ' + thing.type);
function isISomeThing(potentialISomeThing: IThing): potentialISomeThing is ISomeThing {
return potentialISomeThing.type === ThingType.SomeThing;
}
function isIOtherThing(potentialIOtherThing: IThing): potentialIOtherThing is IOtherThing {
return potentialIOtherThing.type === ThingType.OtherThing;
}
}