Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforcing type of key in generic function input

Let's say I have the generic function:

function f<T, K extends keyof T>(obj: T, key: K) {
   ...
}

I would like to enforce the type of T[K] so I could perform type specific actions. For example, using string:

function f<T, K extends keyof T>(obj: T, key: K): string {
    return obj[key].toLowerCase();
}

Is this at all possible without casting things to any?

Edit: To clarify, I'm looking for the ability to disallow certain keys based on the resulting type. Using the example above, something like:

f({a: 123, b: 'abc'}, 'b') //No errors
f({a: 123, b: 'abc'}, 'a') //Typescript error, T['a'] is not string
like image 292
TomerKr Avatar asked Mar 05 '23 18:03

TomerKr


1 Answers

To restrict property names to only those having string value types you can use conditional types in conjunction with mapped types:

type StringProperties<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];

declare function f<T>(obj: T, key: StringProperties<T>): string;

f({a: 123, b: 'abc'}, 'b') // No errors
f({a: 123, b: 'abc'}, 'a') // Error: Argument of type '"a"' is not assignable to parameter of type '"b"'.

Playground

like image 89
Aleksey L. Avatar answered Mar 23 '23 18:03

Aleksey L.