我有一个基类,以及那里的子类。
这些类的实例放在一个具有基类类型的集合中。
class Type extends Object {
public static ID = 'type';
public id = 'type';
constructor() { super(); }
}
class TypeA extends Type {
public static ID = 'type-a';
public id = 'type-a';
constructor() { super(); }
public onlyA() { return 'only A has this method'; }
}
class TypeB extends Type {
public static ID = 'type-b';
public id = 'type-b';
constructor() { super(); }
public onlyB() { return 'only B has this method'; }
}
// Discards subclass type information:
const list: Type[] = [
new TypeA(),
new TypeB()
];
// Has inferred type: Type
const list0 = list[0];
现在,如果我知道正确的类型,我可以使用as
来宣传类型:
const list0asA = list0 as TypeA;
list0asA.onlyA();
然而,我想要做的是创建一个通用函数,它将动态检查实例,并返回提升类型或null
如果它不匹配。
我想出了以下内容,但这不太对劲:
function castOrNull<
C extends typeof Type
>(value: Type, Constructor: C): C | null {
if (value.id !== Constructor.ID) {
return null;
}
return value as C;
}
const list0castA = castOrNull(list0, TypeA);
if (list0castA) {
list0asA.onlyA();
}
问题是我不是试图将变量强制转换为构造函数类型,而是构造函数的实例类型,因此as和return类型不正确。
或者,这确实有效,但它需要明确设置泛型类型,这意味着在使用时指定类型两次,这是不太理想的。
function castOrNull<
T extends Type
>(value: Type, Constructor: typeof Type): T | null {
if (value.id !== Constructor.ID) {
return null;
}
return value as T;
}
const list0upA = castOrNull<TypeA>(list0, TypeA);
if (list0castA) {
list0asA.onlyA();
}
是否可以在不指定类型两次的情况下创建此通用函数?
答案 0 :(得分:1)
从Typescript 2.8开始,类型InstanceType<T>
被添加到标准库中,它从构造函数类型T
中提取其实例的类型。因此,对于您的代码段,您可以将其用于返回类型和强制转换:
function castOrNull<
C extends typeof Type
>(value: Type, Constructor: C): InstanceType<C> | null {
if (value.id !== Constructor.ID) {
return null;
}
return value as InstanceType<C>;
}
// All good now
const list0castA = castOrNull(list0, TypeA);
if (list0castA) {
list0asA.onlyA();
}