1

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
3
  • That is just currying and has nothing to do with pointfree. Commented Jun 25, 2020 at 9:29
  • If you specify the key first you can't really get suggestions, you can get prop(foo)('bar') to give you suggestions Commented Jun 25, 2020 at 9:30
  • Yes, I wanted to use it in pointfee style and got it confused. Commented Jun 25, 2020 at 9:48

3 Answers 3

2

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)
Sign up to request clarification or add additional context in comments.

4 Comments

I am not sure if it was understood how exactly I want to get the suggestions. It wouldn't be possible even in the method I specified in the edit?
@PetrD.Svoboda: Yes, i do not think that is possible.
@H.B., it is possible if return type is generic itself.
Ok. Seems I've missed the question. You are right.
0

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.

Comments

0

If you define your function as I have done here then it is possible.

For you something like:

interface GetFunction<T extends { [K: string]: any }={ [K: string]: any }> {
 <K extends keyof T>(record: T, key1: K1 ): T[K1];
}
export const get : GetFunction;

to use it you would pass the specific kev-value based type if you have it (the default on the generic means you do not have to do this:

const foo = {bar: 1, baz: "2"}; 
const get2 = get as GetFunction<typeof foo>
const answer: 1 = get2( foo, 'bar'); //'bar'|'baz' will be suggestions

Here is a playground link of something similar (which is also on the linked question ) Playground

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.