Skip to content

Commit

Permalink
Add Spread type (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
adridavid committed Jul 30, 2022
1 parent 1cbd351 commit efba9f4
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions index.d.ts
Expand Up @@ -62,6 +62,7 @@ export {OptionalKeysOf} from './source/optional-keys-of';
export {HasOptionalKeys} from './source/has-optional-keys';
export {RequiredKeysOf} from './source/required-keys-of';
export {HasRequiredKeys} from './source/has-required-keys';
export {Spread} from './source/spread';

// Template literal types
export {CamelCase} from './source/camel-case';
Expand Down
1 change: 1 addition & 0 deletions readme.md
Expand Up @@ -162,6 +162,7 @@ Click the type names for complete docs.
- [`HasOptionalKeys`](source/has-optional-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any optional fields.
- [`RequiredKeysOf`](source/required-keys-of.d.ts) - Extract all required keys from the given type.
- [`HasRequiredKeys`](source/has-required-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any required fields.
- [`Spread`](source/spread.d.ts) - Mimic the type inferred by TypeScript when merging two objects using the spread operator.

### JSON

Expand Down
54 changes: 54 additions & 0 deletions source/spread.d.ts
@@ -0,0 +1,54 @@
import type {Except} from './except';
import type {RequiredKeysOf} from './required-keys-of';
import type {Simplify} from './simplify';

type Spread_<FirstType extends object, SecondType extends object> = {
[Key in keyof FirstType]: Key extends keyof SecondType
? FirstType[Key] | Required<SecondType>[Key]
: FirstType[Key];
} & Pick<
SecondType,
RequiredKeysOf<SecondType> | Exclude<keyof SecondType, keyof FirstType>
>;

/**
Mimic the type inferred by TypeScript when merging two objects using the spread operator.
@example
```
import type {Spread} from 'type-fest';
type Foo = {
a: number;
b?: string;
};
type Bar = {
b?: number;
c: boolean;
};
const foo = {a: 1, b: '2'};
const bar = {c: false};
const fooBar = {...foo, ...bar};
type FooBar = Spread<Foo, Bar>;
// type FooBar = {
// a: number;
// b?: string | number | undefined;
// c: boolean;
// }
const baz = (argument: FooBar) => {
// Do something
}
baz(fooBar);
```
@category Object
*/
export type Spread<
FirstType extends object,
SecondType extends object,
> = Simplify<Spread_<FirstType, SecondType>>;
44 changes: 44 additions & 0 deletions test-d/spread.ts
@@ -0,0 +1,44 @@
import {expectType} from 'tsd';
import type {Spread} from '../index';

type Foo = {
a: 'a1';
b?: 'b1';
c: 'c1';
d?: 'd1';
e: 'e1' | undefined;
f: 'f1';
g?: 'g1';
};

type Bar = {
a?: 'a2';
b: 'b2';
c: 'c2';
d?: 'd2';
e?: 'e2';
h: 'h2';
i?: 'i2';
};

type FooBar = Spread<Foo, Bar>;

const foo: Foo = {
a: 'a1',
b: 'b1',
c: 'c1',
d: 'd1',
e: 'e1',
f: 'f1',
g: 'g1',
};

const bar: Bar = {
b: 'b2',
c: 'c2',
h: 'h2',
};

const foobar = {...foo, ...bar};

expectType<FooBar>(foobar);

0 comments on commit efba9f4

Please sign in to comment.