1 | import type {IsEqual} from './is-equal';
|
2 |
|
3 | /**
|
4 | Filter out keys from an object.
|
5 |
|
6 | Returns `never` if `Exclude` is strictly equal to `Key`.
|
7 | Returns `never` if `Key` extends `Exclude`.
|
8 | Returns `Key` otherwise.
|
9 |
|
10 | @example
|
11 | ```
|
12 | type Filtered = Filter<'foo', 'foo'>;
|
13 | //=> never
|
14 | ```
|
15 |
|
16 | @example
|
17 | ```
|
18 | type Filtered = Filter<'bar', string>;
|
19 | //=> never
|
20 | ```
|
21 |
|
22 | @example
|
23 | ```
|
24 | type Filtered = Filter<'bar', 'foo'>;
|
25 | //=> 'bar'
|
26 | ```
|
27 |
|
28 | @see {Except}
|
29 | */
|
30 | type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
|
31 |
|
32 | type ExceptOptions = {
|
33 | /**
|
34 | Disallow assigning non-specified properties.
|
35 |
|
36 | Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`.
|
37 |
|
38 | @default false
|
39 | */
|
40 | requireExactProps?: boolean;
|
41 | };
|
42 |
|
43 | /**
|
44 | Create a type from an object type without certain keys.
|
45 |
|
46 | We recommend setting the `requireExactProps` option to `true`.
|
47 |
|
48 | This type is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). The `Omit` type does not restrict the omitted keys to be keys present on the given type, while `Except` does. The benefits of a stricter type are avoiding typos and allowing the compiler to pick up on rename refactors automatically.
|
49 |
|
50 | This type was proposed to the TypeScript team, which declined it, saying they prefer that libraries implement stricter versions of the built-in types ([microsoft/TypeScript#30825](https://github.com/microsoft/TypeScript/issues/30825#issuecomment-523668235)).
|
51 |
|
52 | @example
|
53 | ```
|
54 | import type {Except} from 'type-fest';
|
55 |
|
56 | type Foo = {
|
57 | a: number;
|
58 | b: string;
|
59 | };
|
60 |
|
61 | type FooWithoutA = Except<Foo, 'a'>;
|
62 | //=> {b: string}
|
63 |
|
64 | const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
|
65 | //=> errors: 'a' does not exist in type '{ b: string; }'
|
66 |
|
67 | type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
|
68 | //=> {a: number} & Partial<Record<"b", never>>
|
69 |
|
70 | const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
|
71 | //=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
|
72 | ```
|
73 |
|
74 | @category Object
|
75 | */
|
76 | export type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {requireExactProps: false}> = {
|
77 | [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
|
78 | } & (Options['requireExactProps'] extends true
|
79 | ? Partial<Record<KeysType, never>>
|
80 | : {});
|