TS Challenge - Merge
Published: 2022-02-04 17:06:38

In this post we are going to try to solve the following TypeScript challenge taken from [Merge Challenge](https://github.com/type-challenges/type-challenges/blob/master/questions/599-medium-merge/README.md)

> Merge two types into a new type. Keys of the second type overrides keys of the first type.

The first thing we have to understand is that the type that we are going to obtain is an **object**, so in the first approximation what we do is to indicate it. So, if `F` and `S` represents objects we can write:

```ts
type Merge<F, S> = {}
```

Graphically we can represent these types as follows:

![types `F` and `S`](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/caid1ph1zlylfn4q9dee.png)

Now we have to keep the attributes of the first and the second of the generics that we are receiving. This is achieved by using the **[keyof](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html)** operator. Now, how do we get the attributes of `F`? Well, simply by writing 

```ts
[P in keyof F]
``` 

which is something like "create an index that consists of all the attributes that are part of the generic `F` and store them in the generic `P` eliminating those that are duplicated".

![`[P in keyof F]`](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5a7j83vj2p9otoxmt42.png)

But, how do we add the attributes of `S`? Well, this is where we have to use the **[union type](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)** to obtain all the attributes that are in both objects. Therefore we will write where we assign to each of the new attributes the value **[never](https://www.typescriptlang.org/docs/handbook/type-compatibility.html#any-unknown-object-void-undefined-null-and-never-assignability)** because in the end what we need is a type with a value:

```ts
type Merge<F, S> = {
  [P in keyof F | keyof S]: never
}
```

Therefore, at this point what we have is something like what is shown in the following figure:

![`[P in keyof F | keyof S]`](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/spfwrbmtplrc7t9q5gp4.png)

Now we simply need to determine the value that will be assigned to the attribute in question. According to the statement of the challenge if the attribute belongs to the second generic then that will be its value while if it belongs to the first it will be that of the first and in the case that it is neither of the two then we will return `never`.

How can we know if an attribute belongs to an object in TypeScript? Well, thanks to the use of the clause **extends (https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html#in-extends-clause)** in such a way that if we take the data type that is formed by all the attributes of the second type `S`(that we already know that it is obtained as `keyof S`) to know if one of the attributes belongs to the same one we will have to write something like the following:

```ts
[P in keyof F | keyof S]: P extends keyof S
```

In other words, we have constructed the data type that is the union of the attributes of `F` and `S` and we have named it `P`. Now what we simply do is to see if the attribute `P` belongs to the set of `S` attributes.

Now we can make use of the **[Conditional Type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)** that TypeScript offers us so that if it is an attribute of `S` we will keep it and otherwise we will check if it is of the first type. 

But what do we have to do to keep the type of the attribute? Well, just access it in the typing of `S`. How? Very simple using the operator `[]`. That is, if you want to access an attribute of `S` you would write something like `S['attribute']`.  Since the attribute that passes the condition is `P`we simply access it in type `S`. In case it is not we will assign `never` to it:

```ts
type Merge<F, S> = {
  [P in keyof F | keyof S]: P extends keyof S ? S[P] : never
}
```

If we repeat this process but this time seeing if the attribute is declared in `F` to assign its value or if not what we do is to assign it `never` since for whatever reason the attribute is not part of any of the objects (which is impossible but so that TypeScript does not give errors we have to complete the conditional operator).

This leaves us with the following result for the challenge:

```ts
type Merge<F, S> = {
  [P in keyof F | keyof S]: P extends keyof S
    ? S[P] 
    : P extends keyof F
      ? F[P]
      : never
}
```

Now if we go to [run the result of our challege](https://tsch.js.org/599/play) to see if we have errors or not we will see that all the tests shown will pass correctly so the proposed solution is correct.

![Checking the solution](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f5ldzhxj68q17vxc3umm.png)