function prop<T, K extends keyof T>(name: K, obj: T): T[K]
function prop<K extends PropertyKey>(name: K):
<T extends Record<K, unknown>>(obj: T) => T[K]
function prop(name: any, obj?: any) {
if (obj === undefined) {
return (obj: any) => obj[name]
} else {
return obj[name]
}
}
// weak types used in impl for simplicity, as they don't matter for the caller.
// also this function body is not really complex
const valid1 = prop('foo', { foo: 'hello1' }); // string
const valid2 = prop('foo')({ foo: 'hello2' }); // string
const invalid = prop('baz')({ foo: 'hello' }); // compile error, `baz` not in { foo: string }
Образец
interface Prop {
<T, K extends keyof T>(name: K, obj: T): T[K];
<K extends PropertyKey>(name: K): <T extends Record<K, unknown>>(obj: T) => T[K]
}
const prop: Prop = (name: any, obj?: any) => {
if (obj === undefined) {
return (obj: any) => obj[name]
} else {
return obj[name]
}
}
// weak types used here for simplicity like in first solution
const valid1 = prop('foo', { foo: 'hello1' }); // string
const valid2 = prop('foo')({ foo: 'hello2' }); // string
const invalid = prop('baz')({ foo: 'hello' }); // never
console.log(valid1, valid2) // hello1 hello2
Пример
Примечание: Перегрузки функций и типы функций не могут использоваться полностью взаимозаменяемо (больше информации здесь или здесь ). В последнем случае может потребоваться аннотировать типы с помощью any
в части реализации функции, чтобы учесть несовместимые типы возвращаемых значений в определенных сигнатурах вызовов - посмотрите эту площадку для примера.