Внутри реализации sample2()
тип TObj[F] extends () => void ? F : never
является неразрешенным условным типом. То есть это условный тип, который зависит от неопределенного в данный момент параметра универсального типа, который необходимо разрешить. В таких случаях компилятор обычно не знает, что с ним делать, и рассматривает его как непрозрачный. (См. microsoft / TypeScript # 23132 для некоторого обсуждения этого.) В частности, он не понимает, что TObj[Tobj[F] extends ()=>void ? F : never]
в конечном итоге придется разрешить в некоторый подтип ()=>void
.
В общем, я бы полностью избегал условных типов, если они не нужны. Компилятор может легче понимать и выводить из сопоставленных типов , таких как Record<K, V>
:
function sample2<K extends PropertyKey, T extends Record<K, () => void>>(
obj: T,
prop: K
) {
obj[prop]();
}
И это ведет себя аналогично, когда вы вызываете его:
const obj2 = {
func() { console.log("func") },
prop: 42
};
sample2(obj2, "func"); // okay,
//sample2(obj, "prop"); // error
// ~~~ <-- number is not assignable to ()=>void
РЕДАКТИРОВАТЬ: чтобы обратиться к оригиналу sample()
, я бы использовал это определение:
function sample<
PK extends PropertyKey,
FK extends PropertyKey,
T extends Record<PK, any> & Record<FK, (v: T[PK]) => void>
>(
comp: T,
prop: PK,
setProp: FK
) {
comp[setProp](comp[prop]);
}
const obj = {
func(z: number) { console.log("called with " + z) },
prop: 42
}
, которое, я думаю, также ведет себя так, как вы хотели бы:
sample(obj, "prop", "func"); // called with 42
sample(obj, "prop", "prop"); // error!
// ~~~ <-- number not assignable to (v: number)=>void
sample(obj, "func", "func"); // error!
// ~~~ <-- (v: number)=>void not assignable to number
Хорошо, надеюсь, это поможет;удачи!
Ссылка на код