How to safely type curried functions in typescript? With particular regard to the following example
interface Prop {
<T, K extends keyof T>(name: K, object: T): T[K];
<K>(name: K): <T>(object: T) => /* ?? */;
}
const prop: Prop = (key, object) => object[key];
const valid1 = prop('foo', { foo: 'hello' }); // string
const valid = prop('foo')({ foo: 'hello' }); // string
// `never`, since `baz` does not exist in { foo: string }
const invalid = prop('baz')({ foo: 'hello' }); // never
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 }
Sample
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
Sample
Note: Function overloads and function types cannot be used completely interchangeably (more infos here or here). With latter, it may be necessary to annotate types with any in the function implementation part to account for incompatible return types in the defined call signatures - checkout this playground for an example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With