I have a base class, and sub-classes there of.
Instances of those classes get put in an collection with the type of the base class.
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];
Now if I know the correct type, I can use as
to promote the type:
const list0asA = list0 as TypeA;
list0asA.onlyA();
What I'd like to do however is create a generic function that will dynamically check the instance, and return either the promoted type or null
if it does not match.
I came up with the following, but it's not quite right:
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();
}
The problem is I'm not trying to cast the variable to the constructors type, but the type of an instance of that constructor, so the as and return types are not correct.
Alternately, this does work, but it requires explicitly setting the generic type, meaning specifying the type twice when used, which is less-than-ideal.
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();
}
Is it possible to create this generic function without specifying the type twice?
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…