我试图在我们的代码库中输入一个遗留函数,它调用某些对象的方法(并应用错误处理等)。我下面的部分(玩具)解决方案可以约束action
类型,但不能给予准确的返回类型(返回any
)。entityGetter
函数应该接受entityA或entityB,并且只接受以'get'
开始的开始可调用键。这后一部分工作正常,这告诉我,获得正确的返回值必须是可能的;但是我不明白为什么action
在访问entity
时没有正确的类型。
我试过给T和A分配默认值,但似乎什么也没改变。
有没有可能在不对entityGetter
函数的(运行时)接口进行任何更改的情况下使其工作?理想情况下,根本没有JS更改,但允许对函数体进行一些更改。
type TEntityA = {
getA: () => string;
getB: () => string;
setC: (arg0: string) => string;
valD: number;
getE: () => object;
};
type TEntityB = {
getA: () => string;
getB: () => number;
setC: (arg0: string) => string;
valD: string;
};
type TEntities = TEntityA | TEntityB;
// type KeysOfType = https://stackoverflow.com/a/64254114
type TGetterKeys<T extends TEntities> = keyof Pick<T, keyof T & (`get${string}`)>;
type TCallableKeys<T extends TEntities> = KeysOfType<T, () => unknown>;
type TGetters<T extends TEntities> = TGetterKeys<T> & TCallableKeys<T>;
const entityGetter = <
T extends TEntities,
A extends TGetters<T>
>(action: A, entity: T) => entity[action]();
// This expression is not callable. Type 'unknown' has no call signatures.
const entityA = new EntityA();
const entityB = new EntityB();
const AgetA = entityGetter('getA', entityA); // => string
const BgetB = entityGetter('getB', entityB); // => number
const AgetX = entityGetter('getX', entityA);
// Argument of type '"getX"' is not assignable to parameter of type '"getA" | "getB" | "getE"'.
操场
1条答案
按热度按时间vsnjm48y1#
TS不明白
T[A]
总是某种函数。所以首先我们需要说服(entity[action] as Function)()
来确保它是可调用的。但是ReturnType<Function>
是any
,所以我们还必须为entityGetter
定义ReturnType。出于与上述相同的原因,简单的
ReturnType<T[A]>
不起作用。TS无法预测 (在这个通用场景中,在使用显式值和类型调用它之前)T[A]
是可调用的,所以它拒绝这样做。所以我们必须手动操作:T[A] extends () => infer R? R: never
。这现在对于TS是可预测的。我还总结了
TGetters
。或
TSPlayground
子节点:
T extends TEntities
作为一个保护,阻止你使用任何不是TEntityA | TEntityB
的对象调用这个函数,即使遵循一般模式 (对象的getter函数以get
或is
开头)。对于键入一个简单的T
就足够了。