1
votes

I have a function for getting value by key from an object that allows me to see suggestions of possible keys in record when using it. The function infers types from it's arguments.

function get<T extends Record<string, any>, K1 extends keyof T>(
    record: T | undefined,
    key1: K1
): T[K1] | undefined

const foo = { bar: 1, baz: 2 }
get(foo, 'bar') // 1, get<{ a: number, b: number }>

Is it possible to convert it to point-free style, keep the strong types and don't lose suggestions? Something similiar to this.

function get<T extends Record<string, any>, K1 extends keyof T>(key1: K1):
    (record: T | undefined) => T[K1] | undefined

const foo = { bar: 1, baz: 2 }
get('bar')(foo) // 1, get<{ a: number, b: number }>

Obviously this doesn't work. I tried multiple variants of the pointfree function, but I couldn't get it to work. I looked at ramda implementation of function prop, which works pointfree, but it doesn't provide suggestions as it allows any string as key.

type prop = <P extends string>(key: P) => <T>(obj: Record<P, T>) => T

const foo = { bar: 1, baz: 2 }
prop('bar')(foo) // 1, prop: <"bar">(key: "bar") => <T>(obj: Record<"bar", T>) => T

EDIT:

Just to be clear I know I wouldn't be able get suggestions without specifying the record first.

prop('...') // no suggestions here
prop('...')(foo) // now I want suggestions
2
That is just currying and has nothing to do with pointfree.H.B.
If you specify the key first you can't really get suggestions, you can get prop(foo)('bar') to give you suggestionsTitian Cernicova-Dragomir
Yes, I wanted to use it in pointfee style and got it confused.Petr D. Svoboda

2 Answers

2
votes

I highly suspect that this is impossible as the order of the dependencies is reversed. If the object were to be supplied first that would not be an issue.

Right now you would have to specify the type of the object manually via the generics, e.g.:

const get = <T extends Record<K1, any>, K1 extends keyof T>(key1: K1) =>
    (record: T) => record[key1];

const foo = { bar: 1, baz: 2 }
get<typeof foo, keyof typeof foo>('bar')(foo)
0
votes

Here is it (works even in typescript 3.3, have no older versions to check):

function get<K extends keyof any>(key: K): <T extends { [key in K]: any }>(x: T) => T[K] {
    return x => x[key]
}

const foo = { bar: 1, baz: "2" }

const x = get('bar')(foo) // number
const y = get('baz')(foo) // string

const z = get('oops')(foo) // Argument of type '{ bar: number; baz: string; }' is not assignable to parameter of type '{ oops: any; }'

Opps. Missed the point about autosuggestions. They don't work in this way as supposed to work left to right in most cases and this one is not exception.