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

1 Answer 1

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

2 Comments

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] };

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.