I've adapted the solution from @Nina to TypeScript, adding an improvement to it.
/**
* Constructs a new object by picking certain properties of the given object.
* Example: `const publicUser = pick(user, ['id', 'name'])`.
* Adapted from https://stackoverflow.com/a/35667463/4034572.
*/
export function pick<T extends object, K extends keyof T>(
object: T,
keys: K[]
): Pick<T, K> {
const entries = keys.filter((k) => k in object).map((k) => [k, object[k]])
return Object.fromEntries(entries)
}
Usage example:
type User = {
readonly id: number
name: string
email: string
password: string
}
type PublicUser = Pick<User, 'id' | 'name'>
const user: User = {
id: 2,
name: 'Albert',
email: '[email protected]',
password: 'pwd',
}
const publicUser: PublicUser = pick(user, ['id', 'name'])
// publicUser is { id: 2, name: 'Albert' }
The nice thing is that TypeScript will not allow you to use an invalid key. For example, doing pick(user, ['xyz']) raises the error TS2322: Type '"xyz"' is not assignable to type 'keyof User'.
And you'll get autocomplete too :)
Improvement
I've added filter((k) => k in object) because without it doing pick(user, ['xyz']) would give { xyz: undefined }, adding a property that doesn't exist on type User.
However, with the filter it correctly gives {}, which is what makes sense since the property xyz does not exist on User.