DEV Community

Discussion on: Advanced TypeScript Exercises - Answer 5

Collapse
 
regevbr profile image
Regev Brody • Edited

Here is an even more generic solution to any type (not just User):

type Config<Type extends object> = {
  [key in keyof Type]-?: boolean;
};

type TrueKeys<Type extends object, Conf extends Config<Type>> = {
    [key in keyof Conf]: Conf[key] extends true ? key : never
}[keyof Type]

type Get<Type extends object> = 
  <Conf extends Config<Type>>(config: Conf) => 
    Required<Pick<Type, TrueKeys<Type, Conf>>>;

type User = {
  name?: string;
  lastname?: string;
  age: number;
};
type UserConfig = Config<User>

// Here declaration to be changed 🔥
declare const getUser: Get<User>

// test cases
const user = getUser({ name: true, lastname: false, age: false })
user.name.toLocaleLowerCase() // this field should be non-optional
user.lastname // this field should not be there and we should have compile error 🛑
user.age // this field should not be there and we should have compile error 🛑

const user2 = getUser({ name: true, lastname: true, age: true })
user2.name.toLocaleLowerCase() // this field should be non-optional
user2.lastname.toLocaleLowerCase() // this field should be non-optional
user2.age.toFixed() // this field should be non-optional

const user3 = getUser({ name: false, lastname: true, age: false })
user3.name // this field should not be there and we should have compile error 🛑
user3.lastname.toLocaleLowerCase() // this field should be non-optional
user3.age // this field should not be there and we should have compile error 🛑

const user4 = getUser({ name: false, lastname: false, age: true })
user4.name // this field should not be there and we should have compile error 🛑
user4.lastname // this field should not be there and we should have compile error 🛑
user4.age.toFixed() // this field should be non-optional

const user5 = getUser({ name: false, lastname: false, age: false })
user5 // user4 should be empty object {}
Enter fullscreen mode Exit fullscreen mode