Skip to content

Commit

Permalink
Merge: Add index signatures support and improve performances (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
skarab42 authored Sep 1, 2022
1 parent 28e55b9 commit 850ac04
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 11 deletions.
38 changes: 28 additions & 10 deletions source/merge.d.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
import type {Except} from './except';
import type {OmitIndexSignature} from './omit-index-signature';
import type {PickIndexSignature} from './pick-index-signature';
import type {Simplify} from './simplify';

type Merge_<FirstType, SecondType> = Except<FirstType, Extract<keyof FirstType, keyof SecondType>> & SecondType;

/**
Merge two types into a new type. Keys of the second type overrides keys of the first type.
@example
```
import type {Merge} from 'type-fest';
type Foo = {
a: number;
b: string;
};
interface Foo {
[x: string]: unknown;
[x: number]: unknown;
foo: string;
bar: symbol;
}
type Bar = {
b: number;
[x: number]: number;
[x: symbol]: unknown;
bar: Date;
baz: boolean;
};
const ab: Merge<Foo, Bar> = {a: 1, b: 2};
export type FooBar = Merge<Foo, Bar>;
// => {
// [x: string]: unknown;
// [x: number]: number;
// [x: symbol]: unknown;
// foo: string;
// bar: Date;
// baz: boolean;
// }
```
@category Object
*/
export type Merge<FirstType, SecondType> = Simplify<Merge_<FirstType, SecondType>>;
export type Merge<Destination, Source> = Simplify<{
[Key in keyof OmitIndexSignature<Destination & Source>]: Key extends keyof Source
? Source[Key]
: Key extends keyof Destination
? Destination[Key]
: never;
} & PickIndexSignature<Destination & Source>>;
46 changes: 45 additions & 1 deletion test-d/merge.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {expectAssignable} from 'tsd';
import {expectAssignable, expectError} from 'tsd';
import type {Merge} from '../index';

type Foo = {
Expand All @@ -12,3 +12,47 @@ type Bar = {

const ab: Merge<Foo, Bar> = {a: 1, b: 2};
expectAssignable<{a: number; b: number}>(ab);

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface FooInterface {
[x: string]: unknown;
[x: number]: unknown;
foo: string;
bar: symbol;
}

type BarType = {
[x: number]: number;
[x: symbol]: boolean;
bar: Date;
baz: boolean;
};

type FooBar = Merge<FooInterface, BarType>;

const fooBar: FooBar = {
'foo-string': 'foo',
42: 24,
[Symbol(42)]: true,
foo: 'foo',
bar: new Date(),
baz: true,
};

expectAssignable<{
[x: string]: unknown;
[x: number]: number;
[x: symbol]: boolean;
foo: string;
bar: Date;
baz: boolean;
}>(fooBar);

declare function setFooBar(fooBar: FooBar): void;

expectError(setFooBar({
[Symbol(42)]: 'life',
foo: 'foo',
bar: new Date(),
baz: true,
}));

0 comments on commit 850ac04

Please sign in to comment.