3

Given an object type that has optional properties, such as:

interface Person {
  name: string;
  age: number;
  friends?: Person[];
  jobName?: string;
}

… I'd like to remove all of its optional properties so that the result is:

interface Person {
  name: string;
  age: number;
}

How can I do that?


Please, note that I can't use Omit<Person, "friends" | "jobName"> because the actual properties are not known in advance. I have to somehow collect the union of keys of all optional properties:

type OptionalKey<Obj extends object> = {
  [Key in keyof Obj]: /* ... */ ? Key : never;
}[keyof Obj];

type PersonOptionalKey = OptionalKey<Person>;
// "friends" | "jobName"

Also, typescript remove optional property is poorly named and doesn't answer my question.

Parzh from Ukraine
  • 7,999
  • 3
  • 34
  • 65
  • 2
    Something [like this](https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgArQM4HsTIN4BQyxyIcAthAFzIZhSgDmA3ESXI9aQK7kBG0ViWQwGEEABMMAfhroo2EAG0AukJIArLHwByFCLNr0mrAL4ECEAB4AHLFDDIwATxsoA0hGcYA8jAAqrhAAPP4ANMgAqgB8yAC8+MhK7sigyADWXlgwyP4qNP7JKsjWkJIYUcjSyCk0IBAAbtDIpkqZztm5apa29o4ubsgAShAAjtzAUBASnt6hsQkAolYIADbcEiGzvgFBoRHLaxshhe2deRHckhAwoNPR0ZfXt-US0T12Dk5ByIfrmz4bGBgDg4KtUFAsDYMPN4mhgAh0vthmMJlMZl4Yf4HgQEDg6E4aH9joDgaDwZDocF5IoFokyJQaAAiAAWbKZEQ4XAAjAAGFpAA)? – spender Jul 05 '21 at 14:11

2 Answers2

6

While the method proposed in the comments removes optional properties it also removes non-optional properties having undefined as a possible value of their type.

interface Person {
    required: string;
    optional?: string;
    maybeUndefined: string | undefined
}

/*
type A = { required: string }
*/
type A = ExcludeOptionalProps<Person>

In case you're looking for a helper type removing only optional keys you may write it as:

type RequiredFieldsOnly<T> = {
    [K in keyof T as T[K] extends Required<T>[K] ? K : never]: T[K]
}

playground link

aleksxor
  • 7,535
  • 1
  • 22
  • 27
  • 1
    I cant get `RequiredFieldsOnly` to work on `typescript@4.5.5`, although it works in the playground. When I look at the intellisense it shows all the properties including the optional ones. Can you elaborate a bit on how the type works? I'm having a hard time wrapping my head around it. – EcksDy Apr 08 '22 at 10:23
  • My current understanding why it should work is the following: `Required[K]` turns all optional fields of T to non optional, then if the original `T[K]` extends(is found on) `Required[K]` then it's good to stay, otherwise it should be `never`. Seems correct, so why isn't working in my local project is beyond me. – EcksDy Apr 08 '22 at 10:33
0

https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

// Removes 'optional' attributes from a type's properties
type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};
 
type MaybeUser = {
  id: string;
  name?: string;
  age?: number;
};
 
type User = Concrete<MaybeUser>;

// results
type User = {
    id: string;
    name: string;
    age: number;
}

Edit: turns out Concrete just turns optional props to required props, it doesnt remove them.

better answer is here: https://stackoverflow.com/a/49579497/19804714