# Extract object type with optional fields in TypeScript

1type GetOptional<T> = any; // implementation23type cases = [4 Expect<Equal<GetOptional<{ foo: number; bar?: string }>, { bar?: string }>>,5 Expect<Equal<GetOptional<{ a: undefined; b?: undefined }>, { b?: undefined }>>6];

Today we discuss GetOptional

Here we consider multiple approaches including new possibilities from TypeScript 4.1

Let's have a look ⤵️

## Pick only optional keys

First things first, we split the solution into 2 parts.

1type OptionalKeys<T> = keyof T;23type GetOptional<T> = Pick<T, OptionalKeys<T>>;

Let's implement `OptionalKeys`

properly as now it returns all the keys from the object type.

If we have an optional key, we can skip the definition of it in the object. It means that given the object with only one optional key, it's allowed to assign empty object to it.

1type WithOptional = { a?: string };2type WithRequired = { a: string };34// ✅ allowed5let obj1: WithOptional = {};6// @ts-expect-error ❌ Property 'a' is missing in type '{}' but required in type 'WithRequired'7let obj2: WithRequired = {};

Knowing that, we can come up with the conditional type `{} extends Pick<T, K> ? T[K] : never`

:

1type OptionalKeys<T> = keyof {2 [K in keyof T]: {} extends Pick<T, K> ? T[K] : never;3};45type GetOptional<T> = Pick<T, OptionalKeys<T>>;

Let's check the solution in Playground – https://tsplay.dev/wenOaN

If we check it on any object type, we will see that it's not working correct

1// "a" | "b"2type Test1 = OptionalKeys<{ a?: 1; b: 2 }>;

But this is because we use `keyof { [K in keyof T]: ... }`

which literally means `keyof T`

. The conditional type is right but we need to return only optional keys. Let's change the solution slightly to make it work.

## Return only optional keys

Let's change the mapped type a bit:

1type Values<T> = T[keyof T];23type OptionalKeys<T> = Values<{4 [K in keyof T]: {} extends Pick<T, K> ? K : never;5}>;67type GetOptional<T> = Pick<T, OptionalKeys<T>>;

What we did here:

- We added
`Values`

which returns not keys but values of the object type - In
`OptionalKeys`

we now return key`K`

instead of value`T[K]`

. In combination with`Values`

we can get the optional keys of`T`

The solution now works as expected https://tsplay.dev/WzL1rN ✅

Is that it? Not really, let's look for the shorter solution 👀

## Shorter solution

Currently we know that the main conditional type is `{} extends Pick<T, K> ? K : never`

Also we know there is Key Remapping via as in TypeScript 4.1 💡

1type MappedTypeWithNewKeys<T> = {2 [K in keyof T as NewKeyType]: T[K];3 // ^^^^^^^^^^^^^4 // This is the new syntax!5};

We can try it in our shorter solution, it will look like that:

1type GetOptional<T> = {2 [K in keyof T as {} extends Pick<T, K> ? K : never]: T[K];3};

Let's sum up it again:

- We figured out how to identify optional keys and came up with the conditional type –
`{} extends Pick<T, K> ? K : never`

- We added
`Values`

first and used it to infer optional keys - Then we found the way to do it with key remapping via operator
`as`

To be able to see the final solution with all the test cases, please have a look at the Playground – https://tsplay.dev/m05JGW

Thank you for your time! 🕛

Have a wonderful evening 🌆 and see you soon! 👋

typescript