Тип (<R>(value: T[K]) => R)
- это не то, что вы ищете; по сути, дженерик c R
является количественно неправильным способом. Это означает «функцию, чей вход имеет тип T[K]
, а выход - любой тип R
, который указывает вызывающая сторона . Это не реально реализовать безопасно. Предположительно, вы действительно имеете в виду, что Реализатор функции должен иметь возможность указать R
, но в TypeScript нет простого способа представить это с помощью обобщений ... вы могли бы поместить R
в качестве другого обобщенного c параметра ObjectButAllKeyIsValueFn
, но тогда вам понадобится один R
на ключ T
. Давайте вернемся назад и посмотрим на это по-другому:
Как насчет того, чтобы определить ObjectButAllKeyIsValueFun
как этот тип:
export type ObjectButAllKeyIsValueFn<T> = {
[K in keyof T]?: ObjectButAllKeyIsValueFn<T[K]> | ((value: T[K]) => unknown)
}
Этот тип отражает идею о том, что функционально-значимым свойствам разрешено возвращать абсолютно любой тип, если вам это нужно. Но, конечно, простое аннотирование значения типом ObjectButallKeyIsValueFn<User>
отбрасывает кучу информации о типе этого значения, вы не знаете, какой тип возвращает каждая функция, или даже если какое-то конкретное свойство вообще является функцией.
Так что давайте откажемся от annot ating переменных как этот тип. Вместо этого, когда мы создаем значения, мы проверяем, что они присваиваются этому типу, не расширяя их. Это даст нам все, что вы хотите IntelliSense. Вот вспомогательная функция и ее применение к User
:
const asObjType = <T>() => <U extends ObjectButAllKeyIsValueFn<T>>(u: U) => u;
const asObjUser = asObjType<User>();
А вот как вы вызываете asObjUser()
:
const z = asObjUser({
name: value => `Hello ${value}`,
address: {
city: city => 1
}
});
/* const z: {
name: (value: string) => string;
address: {
city: (city: string) => number;
};
} */
console.log(z.name("Fred")); // Hello Fred
, которая работает и отслеживает специфику c тип z
. Он также отлавливает ошибки, подобные этой:
const oops = asObjUser({
name: 123, // error!
// number is not assignable to string | ((value: string) => unknown) | undefined
});
Итак, надеюсь, этого достаточно для достижения прогресса. Удачи!
Детская площадка ссылка на код