2

UPDATE
i found this solution

type Merge<T, U> = {
  [K in keyof T | keyof U]: K extends keyof U? U[K]: K extends keyof T? T[K]: never;
};

is there something like this in typescript?(spread operator)

type Merge<T, U> = ...[K in keyof T]: T[K], ...[K in keyof U]: U[K]

my task is to Merge two types into a new type. Keys of the second type overrides keys of the first type. for example:

interface User {
  id: string;
  name: string;
  age: number;
  role: "admin" | "moderator" | "user";
  occupation: string;
}
interface User2 {
  id: string;
  name: string;
  age: boolean;
}

type mergedType = Merge<User, User2>

after merge, interface type will be something like this->

{
  id: string;
  name: string;
  age: boolean;
  role: "admin" | "moderator" | "user";
  occupation: string;
}
6
  • 1
    age: boolean?? Commented Feb 13, 2022 at 14:19
  • just an example Commented Feb 13, 2022 at 14:20
  • @namizo - It makes a big difference, because if age has type number in one of them and type boolean in the other, it markedly complicates merging. Commented Feb 13, 2022 at 14:20
  • task says: Keys of the second type overrides keys of the first type. if type of age was number in first interface and boolean in second, age: boolean should be final result Commented Feb 13, 2022 at 14:22
  • What do you want to see if the properties from the second type are optional? What should Merge<{a: string}, {a?: number}> be? Commented Feb 13, 2022 at 15:11

2 Answers 2

2

If the types were never in conflict, it would be just be User & User2, but in your example User has age: number and User2 has age: boolean, so they conflict.

You can handle that the way you've said you want to (using the second one's definition) with a mapped type using a conditional type to pick the property type from B if it's there or from A if it isn't, intersected with the second type you're merging:

type MergeTypes<A, B> = {
    [key in keyof A]: key extends keyof B ? B[key] : A[key];
} & B;

(Edit: Or the rather simpler type MergeTypes<A, B> = Omit<A, keyof B> & B; as pointed out by M. Erim Tuzcuoglu and this answer to another question. Doh!)

Usage:

type MergedType = MergeTypes<User, User2>;

Playground link

Here's how that works:

  • key in keyof A says that the mapped type will have a key for each key of the type A
  • key extends keyof B checks to see if the key is also a key of type B
    • If it is, we use B[key] as the property type; if it isn't, we use A[key]
  • The result of the above only has the properties that A has (but with B's type for them if they both have it), it won't have ones that only exist on B. So we add & B at the end to add them.
Sign up to request clarification or add additional context in comments.

Comments

2

I think you're looking for this

Here is a working example:

interface User {
  id: string;
  name: string;
  age: number;
  role: "admin" | "moderator" | "user";
  occupation: string;
}
interface User2 {
  id: string;
  name: string;
  age: boolean;
}

type Modify<T, R> = Omit<T, keyof R> & R;

var x: Modify<User, User2> = {id: '123', name: 'name', age: true, occupation: 'occ', role: 'admin'};
console.log(x);

1 Comment

Omit<T, keyof R> headslap Yes, I should have thought of that instead of a mapped conditional type. (This question is almost a duplicate of that one...)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.