1

I'm looking to type a generic object and have properties of that object return in a typed array. The ability to get a singular typed property from an object is documented and works, however i'm unable to get this to work with an array. Seems the 'union type'.

// from the documentation 
// @ http://www.typescriptlang.org/docs/handbook/advanced-types.html
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
    return o[name];
}

const a = getProperty(person, 'age');
// a: number
const n = getProperty(person, 'name');
// n: string

const getProperties = <T>(obj: T, keys: Array<keyof T>) => keys.map((arg) => getProperty(obj, arg));

const [a2, n2] = getProperties(person, ['name', 'age']);
// result:
// a2: string | number
// n2: string | number

// what i want:
// a2: string
// n2: number
blugavere
  • 107
  • 1
  • 6

1 Answers1

0

The problem is that keys can be any key of T so when you call getProperty inside getProperties the result will be of T[keyof T] meaning any value of T. For getProperty(person, 'age') it works because name will be inferred as the string literal type 'age' and the result will thus be T['age'] which is number.

To accomplish what you want, we need a separate generic parameter for each key that will be passed. We can't support an arbitrary amount of keys but, using overloads, we can support a certain finite amount of keys which will be good enough for most cases (I added overloads for up to 3 keys, you can easily add more):

const person = {
    age: 1,
    name: ""
}
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
    return o[name];
}


function getProperties<T, K extends keyof T, K2 extends keyof T, K3 extends keyof T>(obj: T, keys: [K, K2, K3]): [T[K], T[K2], T[K3]]
function getProperties<T, K extends keyof T, K2 extends keyof T>(obj: T, keys: [K, K2]): [T[K], T[K2]]
function getProperties<T, K extends keyof T>(obj: T, keys: [K]): [T[K]]
function getProperties<T>(obj: T, keys: Array<keyof T>) {
    return keys.map((arg) => getProperty(obj, arg));
} 

const [a2, n2] = getProperties(person, ['name', 'age']); // a2: string, n2: number
Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357
  • thanks! this solved the array problem; is there a way to solve a similar issue with a map interface? const getProperties = (map: { [key: string]: K }) => { [key: string]: T[K] }; – blugavere Jun 09 '18 at 18:19
  • this was answered in https://stackoverflow.com/questions/50822693/how-to-infer-typed-mapvalues-using-lookups-in-typescript/50823307#50823307 – blugavere Jun 12 '18 at 20:38