'How to create a type (named or anonymous) which is another type with some of its properties set to non-optional?

Suppose I have the following type:

interface Person {
  name: string,
  // ... a whole lot of other properties...
  bio?: string 
}

What is the best way of creating another type based on Person but with the bio property being non-optional?

This is what I'm currently doing for creating a named type:

interface PersonWithBio extends Person {
  bio: NonNullable<Person['bio']>
}
let personWithBio1: PersonWithBio;

And for creating an anonymous type:

let personWithBio2: Person & { bio: NonNullable<Person['bio']> }

Is there a better way without having to manually overwrite the bio property?



Solution 1:[1]

You can use mapped types with modifiers:

interface Person {
  name: string,
  age: number,
  bio?: string,
  bio2?: string;
  bio3?: string;
}

type WithNonOptional<T, Key extends keyof T> = T & { [K in Key]-?: T[K] };

type Person2 = WithNonOptional<Person, 'bio' | 'bio2'>;

// equivalent to:
// type Person2 = Person & {
//   bio: string;
//   bio2: string;
// }

This will make the bio and bio2 keys non-optional but let bio3 remain optional.

To make all fields non optional, there's a snippet in the docs linked above:

type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};

type Person3 = Concrete<Person>;

// equivalent to:
// type Person3 = {
//  name: string;
//  age: number;
//  bio: string;
//  bio2: string;
//  bio3: string;
// }

Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dogbert