type-fest 2.9.0 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -12,11 +12,13 @@ export {MergeExclusive} from './source/merge-exclusive';
12
12
  export {RequireAtLeastOne} from './source/require-at-least-one';
13
13
  export {RequireExactlyOne} from './source/require-exactly-one';
14
14
  export {RequireAllOrNone} from './source/require-all-or-none';
15
+ export {RemoveIndexSignature} from './source/remove-index-signature';
15
16
  export {PartialDeep} from './source/partial-deep';
16
17
  export {ReadonlyDeep} from './source/readonly-deep';
17
18
  export {LiteralUnion} from './source/literal-union';
18
19
  export {Promisable} from './source/promisable';
19
20
  export {Opaque} from './source/opaque';
21
+ export {InvariantOf} from './source/invariant-of';
20
22
  export {SetOptional} from './source/set-optional';
21
23
  export {SetRequired} from './source/set-required';
22
24
  export {ValueOf} from './source/value-of';
@@ -37,6 +39,7 @@ export {SetReturnType} from './source/set-return-type';
37
39
  export {Asyncify} from './source/asyncify';
38
40
  export {Simplify} from './source/simplify';
39
41
  export {Jsonify} from './source/jsonify';
42
+ export {Schema} from './source/schema';
40
43
  export {LiteralToPrimitive} from './source/literal-to-primitive';
41
44
  export {
42
45
  PositiveInfinity,
@@ -50,6 +53,7 @@ export {
50
53
  NegativeInteger,
51
54
  NonNegativeInteger,
52
55
  } from './source/numeric';
56
+ export {StringKeyOf} from './source/string-key-of';
53
57
 
54
58
  // Template literal types
55
59
  export {CamelCase} from './source/camel-case';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-fest",
3
- "version": "2.9.0",
3
+ "version": "2.11.2",
4
4
  "description": "A collection of essential TypeScript types",
5
5
  "license": "(MIT OR CC0-1.0)",
6
6
  "repository": "sindresorhus/type-fest",
package/readme.md CHANGED
@@ -99,10 +99,12 @@ Click the type names for complete docs.
99
99
  - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys.
100
100
  - [`RequireExactlyOne`](source/require-exactly-one.d.ts) - Create a type that requires exactly a single key of the given keys and disallows more.
101
101
  - [`RequireAllOrNone`](source/require-all-or-none.d.ts) - Create a type that requires all of the given keys or none of the given keys.
102
+ - [`RemoveIndexSignature`](source/remove-index-signature.d.ts) - Create a type that only has explicitly defined properties, absent of any index signatures.
102
103
  - [`PartialDeep`](source/partial-deep.d.ts) - Create a deeply optional version of another type. Use [`Partial<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) if you only need one level deep.
103
104
  - [`ReadonlyDeep`](source/readonly-deep.d.ts) - Create a deeply immutable version of an `object`/`Map`/`Set`/`Array` type. Use [`Readonly<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) if you only need one level deep.
104
105
  - [`LiteralUnion`](source/literal-union.d.ts) - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for [Microsoft/TypeScript#29729](https://github.com/Microsoft/TypeScript/issues/29729).
105
106
  - [`Opaque`](source/opaque.d.ts) - Create an [opaque type](https://codemix.com/opaque-types-in-javascript/).
107
+ - [`InvariantOf`](source/invariant-of.d.ts) - Create an [invariant type](https://basarat.gitbook.io/typescript/type-system/type-compatibility#footnote-invariance), which is a type that does not accept supertypes and subtypes.
106
108
  - [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional.
107
109
  - [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required.
108
110
  - [`ValueOf`](source/value-of.d.ts) - Create a union of the given object's values, and optionally specify which keys to get the values from.
@@ -118,6 +120,8 @@ Click the type names for complete docs.
118
120
  - [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type.
119
121
  - [`Simplify`](source/simplify.d.ts) - Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
120
122
  - [`Get`](source/get.d.ts) - Get a deeply-nested property from an object using a key path, like [Lodash's `.get()`](https://lodash.com/docs/latest#get) function.
123
+ - [`StringKeyOf`](source/string-key-of.d.ts) - Get keys of the given type as strings.
124
+ - [`Schema`](source/schema.d.ts) - Create a deep version of another object type where property values are recursively replaced into a given value type.
121
125
 
122
126
  ### JSON
123
127
 
@@ -162,22 +166,22 @@ Click the type names for complete docs.
162
166
 
163
167
  ### Change case
164
168
 
165
- - [`CamelCase`](source/camel-case.d.ts) Convert a string literal to camel-case (`fooBar`).
166
- - [`CamelCasedProperties`](source/camel-cased-properties.d.ts) Convert object properties to camel-case (`fooBar`).
167
- - [`CamelCasedPropertiesDeep`](source/camel-cased-properties-deep.d.ts) Convert object properties to camel-case recursively (`fooBar`).
168
- - [`KebabCase`](source/kebab-case.d.ts) Convert a string literal to kebab-case (`foo-bar`).
169
- - [`KebabCasedProperties`](source/kebab-cased-properties.d.ts) Convert a object properties to kebab-case recursively (`foo-bar`).
170
- - [`KebabCasedPropertiesDeep`](source/kebab-cased-properties-deep.d.ts) Convert object properties to kebab-case (`foo-bar`).
171
- - [`PascalCase`](source/pascal-case.d.ts) Converts a string literal to pascal-case (`FooBar`)
172
- - [`PascalCasedProperties`](source/pascal-cased-properties.d.ts) Converts object properties to pascal-case (`FooBar`)
173
- - [`PascalCasedPropertiesDeep`](source/pascal-cased-properties-deep.d.ts) Converts object properties to pascal-case (`FooBar`)
174
- - [`SnakeCase`](source/snake-case.d.ts) Convert a string literal to snake-case (`foo_bar`).
175
- - [`SnakeCasedProperties`](source/snake-cased-properties-deep.d.ts) Convert object properties to snake-case (`foo_bar`).
176
- - [`SnakeCasedPropertiesDeep`](source/snake-cased-properties-deep.d.ts) Convert object properties to snake-case recursively (`foo_bar`).
169
+ - [`CamelCase`](source/camel-case.d.ts) - Convert a string literal to camel-case (`fooBar`).
170
+ - [`CamelCasedProperties`](source/camel-cased-properties.d.ts) - Convert object properties to camel-case (`fooBar`).
171
+ - [`CamelCasedPropertiesDeep`](source/camel-cased-properties-deep.d.ts) - Convert object properties to camel-case recursively (`fooBar`).
172
+ - [`KebabCase`](source/kebab-case.d.ts) - Convert a string literal to kebab-case (`foo-bar`).
173
+ - [`KebabCasedProperties`](source/kebab-cased-properties.d.ts) - Convert a object properties to kebab-case recursively (`foo-bar`).
174
+ - [`KebabCasedPropertiesDeep`](source/kebab-cased-properties-deep.d.ts) - Convert object properties to kebab-case (`foo-bar`).
175
+ - [`PascalCase`](source/pascal-case.d.ts) - Converts a string literal to pascal-case (`FooBar`)
176
+ - [`PascalCasedProperties`](source/pascal-cased-properties.d.ts) - Converts object properties to pascal-case (`FooBar`)
177
+ - [`PascalCasedPropertiesDeep`](source/pascal-cased-properties-deep.d.ts) - Converts object properties to pascal-case (`FooBar`)
178
+ - [`SnakeCase`](source/snake-case.d.ts) - Convert a string literal to snake-case (`foo_bar`).
179
+ - [`SnakeCasedProperties`](source/snake-cased-properties-deep.d.ts) - Convert object properties to snake-case (`foo_bar`).
180
+ - [`SnakeCasedPropertiesDeep`](source/snake-cased-properties-deep.d.ts) - Convert object properties to snake-case recursively (`foo_bar`).
177
181
  - [`ScreamingSnakeCase`](source/screaming-snake-case.d.ts) - Convert a string literal to screaming-snake-case (`FOO_BAR`).
178
- - [`DelimiterCase`](source/delimiter-case.d.ts) Convert a string literal to a custom string delimiter casing.
179
- - [`DelimiterCasedProperties`](source/delimiter-cased-properties.d.ts) Convert object properties to a custom string delimiter casing.
180
- - [`DelimiterCasedPropertiesDeep`](source/delimiter-cased-properties-deep.d.ts) Convert object properties to a custom string delimiter casing recursively.
182
+ - [`DelimiterCase`](source/delimiter-case.d.ts) - Convert a string literal to a custom string delimiter casing.
183
+ - [`DelimiterCasedProperties`](source/delimiter-cased-properties.d.ts) - Convert object properties to a custom string delimiter casing.
184
+ - [`DelimiterCasedPropertiesDeep`](source/delimiter-cased-properties-deep.d.ts) - Convert object properties to a custom string delimiter casing recursively.
181
185
 
182
186
  ### Miscellaneous
183
187
 
@@ -188,17 +192,20 @@ Click the type names for complete docs.
188
192
 
189
193
  *If we decline a type addition, we will make sure to document the better solution here.*
190
194
 
191
- - [`Diff` and `Spread`](https://github.com/sindresorhus/type-fest/pull/7) - The PR author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.
195
+ - [`Diff` and `Spread`](https://github.com/sindresorhus/type-fest/pull/7) - The pull request author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.
192
196
  - [`Dictionary`](https://github.com/sindresorhus/type-fest/issues/33) - You only save a few characters (`Dictionary<number>` vs `Record<string, number>`) from [`Record`](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type), which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have `Map` in JavaScript now.
193
197
  - [`ExtractProperties` and `ExtractMethods`](https://github.com/sindresorhus/type-fest/pull/4) - The types violate the single responsibility principle. Instead, refine your types into more granular type hierarchies.
194
198
  - [`Url2Json`](https://github.com/sindresorhus/type-fest/pull/262) - Inferring search parameters from a URL string is a cute idea, but not very useful in practice, since search parameters are usually dynamic and defined separately.
195
- - [`Nullish`](https://github.com/sindresorhus/type-fest/pull/318) - The type only saves a couple of characters, not everyone knows what nullish means, and I'm also trying to [get away from `null`](https://github.com/sindresorhus/meta/discussions/7).
199
+ - [`Nullish`](https://github.com/sindresorhus/type-fest/pull/318) - The type only saves a couple of characters, not everyone knows what "nullish" means, and I'm also trying to [get away from `null`](https://github.com/sindresorhus/meta/discussions/7).
200
+ - [`TitleCase`](https://github.com/sindresorhus/type-fest/pull/303) - It's not solving a common need and is a better fit for a separate package.
201
+ - [`ExtendOr` and `ExtendAnd`](https://github.com/sindresorhus/type-fest/pull/247) - The benefits don't outweigh having to learn what they mean.
196
202
 
197
203
  ## Alternative type names
198
204
 
199
205
  *If you know one of our types by a different name, add it here for discovery.*
200
206
 
201
207
  - `PartialBy` - See [`SetOptional`](https://github.com/sindresorhus/type-fest/blob/main/source/set-optional.d.ts)
208
+ - `RecordDeep`- See [`Schema`](https://github.com/sindresorhus/type-fest/blob/main/source/schema.d.ts)
202
209
 
203
210
  ## Tips
204
211
 
@@ -607,7 +614,7 @@ There are many advanced types most users don't know about.
607
614
  ```
608
615
  </details>
609
616
 
610
- - [`ReturnType<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) Obtain the return type of a function type.
617
+ - [`ReturnType<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype) - Obtain the return type of a function type.
611
618
  <details>
612
619
  <summary>
613
620
  Example
@@ -642,7 +649,7 @@ There are many advanced types most users don't know about.
642
649
  ```
643
650
  </details>
644
651
 
645
- - [`InstanceType<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype) Obtain the instance type of a constructor function type.
652
+ - [`InstanceType<T>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype) - Obtain the instance type of a constructor function type.
646
653
  <details>
647
654
  <summary>
648
655
  Example
@@ -695,7 +702,7 @@ There are many advanced types most users don't know about.
695
702
  ```
696
703
  </details>
697
704
 
698
- - [`Omit<T, K>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) Constructs a type by picking all properties from T and then removing K.
705
+ - [`Omit<T, K>`](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys) - Constructs a type by picking all properties from T and then removing K.
699
706
  <details>
700
707
  <summary>
701
708
  Example
@@ -45,7 +45,7 @@ const result: DelimiterCasedPropertiesDeep<UserWithFriends, '-'> = {
45
45
  export type DelimiterCasedPropertiesDeep<
46
46
  Value,
47
47
  Delimiter extends string,
48
- > = Value extends Function
48
+ > = Value extends Function | Date | RegExp
49
49
  ? Value
50
50
  : Value extends Array<infer U>
51
51
  ? Array<DelimiterCasedPropertiesDeep<U, Delimiter>>
package/source/get.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {StringDigit} from '../source/utilities';
2
2
  import {Split} from './split';
3
+ import {StringKeyOf} from './string-key-of';
3
4
 
4
5
  type GetOptions = {
5
6
  strict?: boolean;
@@ -11,7 +12,7 @@ Like the `Get` type but receives an array of strings as a path parameter.
11
12
  type GetWithPath<BaseType, Keys extends readonly string[], Options extends GetOptions = {}> =
12
13
  Keys extends []
13
14
  ? BaseType
14
- : Keys extends [infer Head, ...infer Tail]
15
+ : Keys extends readonly [infer Head, ...infer Tail]
15
16
  ? GetWithPath<
16
17
  PropertyOf<BaseType, Extract<Head, string>, Options>,
17
18
  Extract<Tail, string[]>,
@@ -97,7 +98,7 @@ type WithStringsKeys = keyof WithStrings;
97
98
  ```
98
99
  */
99
100
  type WithStringKeys<BaseType extends Record<string | number, any>> = {
100
- [Key in `${Extract<keyof BaseType, string | number>}`]: BaseType[Key]
101
+ [Key in StringKeyOf<BaseType>]: BaseType[Key]
101
102
  };
102
103
 
103
104
  /**
@@ -138,7 +139,7 @@ Use-case: Retrieve a property from deep inside an API response or some other com
138
139
  import {Get} from 'type-fest';
139
140
  import * as lodash from 'lodash';
140
141
 
141
- const get = <BaseType, Path extends string>(object: BaseType, path: Path): Get<BaseType, Path> =>
142
+ const get = <BaseType, Path extends string | readonly string[]>(object: BaseType, path: Path): Get<BaseType, Path> =>
142
143
  lodash.get(object, path);
143
144
 
144
145
  interface ApiResponse {
@@ -160,6 +161,11 @@ const getName = (apiResponse: ApiResponse) =>
160
161
  get(apiResponse, 'hits.hits[0]._source.name');
161
162
  //=> Array<{given: string[]; family: string}>
162
163
 
164
+ // Path also supports a readonly array of strings
165
+ const getNameWithPathArray = (apiResponse: ApiResponse) =>
166
+ get(apiResponse, ['hits','hits', '0', '_source', 'name'] as const);
167
+ //=> Array<{given: string[]; family: string}>
168
+
163
169
  // Strict mode:
164
170
  Get<string[], '3', {strict: true}> //=> string | undefined
165
171
  Get<Record<string, string>, 'foo', {strict: true}> // => string | undefined
@@ -169,5 +175,5 @@ Get<Record<string, string>, 'foo', {strict: true}> // => string | undefined
169
175
  @category Array
170
176
  @category Template literal
171
177
  */
172
- export type Get<BaseType, Path extends string, Options extends GetOptions = {}> =
173
- GetWithPath<BaseType, ToPath<Path>, Options>;
178
+ export type Get<BaseType, Path extends string | readonly string[], Options extends GetOptions = {}> =
179
+ GetWithPath<BaseType, Path extends string ? ToPath<Path> : Path, Options>;
@@ -1,3 +1,5 @@
1
+ import {Primitive} from './primitive';
2
+
1
3
  /**
2
4
  Returns a boolean for whether the two given types are equal.
3
5
 
@@ -35,3 +37,8 @@ the inferred tuple `U` and a tuple of length `B`, then extracts the length of tu
35
37
  export type Subtract<A extends number, B extends number> = BuildTuple<A> extends [...(infer U), ...BuildTuple<B>]
36
38
  ? TupleLength<U>
37
39
  : never;
40
+
41
+ /**
42
+ Matches any primitive, `Date`, or `RegExp` value.
43
+ */
44
+ export type BuiltIns = Primitive | Date | RegExp;
@@ -0,0 +1,72 @@
1
+ import {Opaque} from './opaque';
2
+
3
+ /**
4
+ Create an [invariant type](https://basarat.gitbook.io/typescript/type-system/type-compatibility#footnote-invariance), which is a type that does not accept supertypes and subtypes.
5
+
6
+ Use-case:
7
+ - Prevent runtime errors that may occur due to assigning subtypes to supertypes.
8
+ - Improve type signature of object methods like [`Object.keys()` or `Object.entries()`](https://github.com/microsoft/TypeScript/pull/12253#issuecomment-263132208) by sealing the object type.
9
+
10
+ @example
11
+ ```
12
+ class Animal {
13
+ constructor(public name: string){}
14
+ }
15
+
16
+ class Cat extends Animal {
17
+ meow() {}
18
+ }
19
+
20
+ let animalArray: Animal[] = [animal];
21
+ let catArray: Cat[] = [cat];
22
+
23
+ animalArray = catArray; // Okay if covariant
24
+ animalArray.push(new Animal('another animal')); // Pushed an animal into catArray
25
+ catArray.forEach(c => c.meow()); // Allowed but, error at runtime
26
+
27
+ let invariantAnimalArray: InvariantOf<Animal>[] = [animal] as InvariantOf<Animal>[];
28
+ let invariantCatArray: InvariantOf<Cat>[] = [cat] as InvariantOf<Cat>[];
29
+
30
+ invariantAnimalArray = invariantCatArray; // Error: Type 'InvariantOf<Cat>[]' is not assignable to type 'InvariantOf<Animal>[]'.
31
+ ```
32
+
33
+ @example
34
+ ```
35
+ // In covariance (default)
36
+
37
+ interface FooBar {
38
+ foo: number;
39
+ bar: string
40
+ }
41
+
42
+ interface FooBarBaz extends FooBar {
43
+ baz: boolean
44
+ }
45
+
46
+ declare const fooBar: FooBar
47
+ declare const fooBarBaz: FooBarBaz
48
+
49
+ function keyOfFooBar(fooBar: FooBar) {
50
+ return Object.keys(fooBar) as (keyof FooBar)[]
51
+ }
52
+
53
+ keyOfFooBar(fooBar) //=> (keyof FooBar)[]
54
+ keyOfFooBar(fooBarBaz) //=> (keyof FooBar)[] but, (keyof FooBarBaz)[] at runtime
55
+
56
+ // In invariance
57
+
58
+ export function invariantOf<Type>(value: Type): InvariantOf<Type> {
59
+ return value as InvariantOf<Type>;
60
+ }
61
+
62
+ function keyOfInvariantFooBar(fooBar: InvariantOf<FooBar>) {
63
+ return Object.keys(fooBar) as (keyof FooBar)[]
64
+ }
65
+
66
+ keyOfInvariantFooBar(invariantOf(fooBar)); // (keyof FooBar)[]
67
+ keyOfInvariantFooBar(invariantOf(fooBarBaz)); // Error: Argument of type 'InvariantOf<FooBarBaz>' is not assignable to parameter of type 'InvariantOf<FooBar>'.
68
+ ```
69
+
70
+ @category Type
71
+ */
72
+ export type InvariantOf<Type> = Opaque<Type, (argument: Type) => Type>;
@@ -28,8 +28,8 @@ const pet: Pet2 = '';
28
28
  ```
29
29
 
30
30
  @category Type
31
- */
31
+ */
32
32
  export type LiteralUnion<
33
33
  LiteralType,
34
34
  BaseType extends Primitive,
35
- > = LiteralType | (BaseType & {_?: never});
35
+ > = LiteralType | (BaseType & Record<never, never>);
@@ -214,6 +214,7 @@ declare namespace PackageJson {
214
214
  | 'import'
215
215
  | 'require'
216
216
  | 'node'
217
+ | 'node-addons'
217
218
  | 'deno'
218
219
  | 'browser'
219
220
  | 'electron'
@@ -1,4 +1,4 @@
1
- import {Primitive} from './primitive';
1
+ import {BuiltIns} from './internal';
2
2
 
3
3
  /**
4
4
  Create a type from another type with all keys and nested keys set to optional.
@@ -33,8 +33,8 @@ settings = applySavedSettings({textEditor: {fontWeight: 500}});
33
33
  @category Set
34
34
  @category Map
35
35
  */
36
- export type PartialDeep<T> = T extends Primitive
37
- ? Partial<T>
36
+ export type PartialDeep<T> = T extends BuiltIns
37
+ ? T
38
38
  : T extends Map<infer KeyType, infer ValueType>
39
39
  ? PartialMapDeep<KeyType, ValueType>
40
40
  : T extends Set<infer ItemType>
@@ -42,7 +42,7 @@ const result: PascalCasedPropertiesDeep<UserWithFriends> = {
42
42
  @category Template literal
43
43
  @category Object
44
44
  */
45
- export type PascalCasedPropertiesDeep<Value> = Value extends Function
45
+ export type PascalCasedPropertiesDeep<Value> = Value extends Function | Date | RegExp
46
46
  ? Value
47
47
  : Value extends Array<infer U>
48
48
  ? Array<PascalCasedPropertiesDeep<U>>
@@ -1,4 +1,4 @@
1
- import {Primitive} from './primitive';
1
+ import {BuiltIns} from './internal';
2
2
 
3
3
  /**
4
4
  Convert `object`s, `Map`s, `Set`s, and `Array`s and all of their keys/elements into immutable structures recursively.
@@ -34,11 +34,17 @@ data.foo.push('bar');
34
34
  @category Set
35
35
  @category Map
36
36
  */
37
- export type ReadonlyDeep<T> = T extends Primitive | ((...arguments: any[]) => unknown)
37
+ export type ReadonlyDeep<T> = T extends BuiltIns
38
38
  ? T
39
- : T extends ReadonlyMap<infer KeyType, infer ValueType>
39
+ : T extends (...arguments: any[]) => unknown
40
+ ? {} extends ReadonlyObjectDeep<T>
41
+ ? T
42
+ : HasMultipleCallSignatures<T> extends true
43
+ ? T
44
+ : ((...arguments: Parameters<T>) => ReturnType<T>) & ReadonlyObjectDeep<T>
45
+ : T extends Readonly<ReadonlyMap<infer KeyType, infer ValueType>>
40
46
  ? ReadonlyMapDeep<KeyType, ValueType>
41
- : T extends ReadonlySet<infer ItemType>
47
+ : T extends Readonly<ReadonlySet<infer ItemType>>
42
48
  ? ReadonlySetDeep<ItemType>
43
49
  : T extends object
44
50
  ? ReadonlyObjectDeep<T>
@@ -48,13 +54,13 @@ export type ReadonlyDeep<T> = T extends Primitive | ((...arguments: any[]) => un
48
54
  Same as `ReadonlyDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `ReadonlyDeep`.
49
55
  */
50
56
  interface ReadonlyMapDeep<KeyType, ValueType>
51
- extends ReadonlyMap<ReadonlyDeep<KeyType>, ReadonlyDeep<ValueType>> {}
57
+ extends Readonly<ReadonlyMap<ReadonlyDeep<KeyType>, ReadonlyDeep<ValueType>>> {}
52
58
 
53
59
  /**
54
60
  Same as `ReadonlyDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `ReadonlyDeep`.
55
61
  */
56
62
  interface ReadonlySetDeep<ItemType>
57
- extends ReadonlySet<ReadonlyDeep<ItemType>> {}
63
+ extends Readonly<ReadonlySet<ReadonlyDeep<ItemType>>> {}
58
64
 
59
65
  /**
60
66
  Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper for `ReadonlyDeep`.
@@ -62,3 +68,18 @@ Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper fo
62
68
  type ReadonlyObjectDeep<ObjectType extends object> = {
63
69
  readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]>
64
70
  };
71
+
72
+ /**
73
+ Test if the given function has multiple call signatures.
74
+
75
+ Needed to handle the case of a single call signature with properties.
76
+
77
+ Multiple call signatures cannot currently be supported due to a TypeScript limitation.
78
+ @see https://github.com/microsoft/TypeScript/issues/29732
79
+ */
80
+ type HasMultipleCallSignatures<T extends (...arguments: any[]) => unknown> =
81
+ T extends {(...arguments: infer A): unknown; (...arguments: any[]): unknown}
82
+ ? unknown[] extends A
83
+ ? false
84
+ : true
85
+ : false;
@@ -0,0 +1,98 @@
1
+ /**
2
+ Remove any index signatures from the given object type, so that only explicitly defined properties remain.
3
+
4
+ Use-cases:
5
+ - Remove overly permissive signatures from third-party types.
6
+
7
+ This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
8
+
9
+ It relies on the fact that an empty object (`{}`) is assignable to an object with just an index signature, like `Record<string, unknown>`, but not to an object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`.
10
+
11
+ (The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.)
12
+
13
+ ```
14
+ const indexed: Record<string, unknown> = {}; // Allowed
15
+
16
+ const keyed: Record<'foo', unknown> = {}; // Error
17
+ // => TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
18
+ ```
19
+
20
+ Instead of causing a type error like the above, you can also use a [conditional type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html) to test whether a type is assignable to another:
21
+
22
+ ```
23
+ type Indexed = {} extends Record<string, unknown>
24
+ ? '✅ `{}` is assignable to `Record<string, unknown>`'
25
+ : '❌ `{}` is NOT assignable to `Record<string, unknown>`';
26
+ // => '✅ `{}` is assignable to `Record<string, unknown>`'
27
+
28
+ type Keyed = {} extends Record<'foo' | 'bar', unknown>
29
+ ? "✅ `{}` is assignable to `Record<'foo' | 'bar', unknown>`"
30
+ : "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`";
31
+ // => "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`"
32
+ ```
33
+
34
+ Using a [mapped type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration), you can then check for each `KeyType` of `ObjectType`...
35
+
36
+ ```
37
+ type RemoveIndexSignature<ObjectType> = {
38
+ [KeyType in keyof ObjectType // Map each key of `ObjectType`...
39
+ ]: ObjectType[KeyType]; // ...to its original value, i.e. `RemoveIndexSignature<Foo> == Foo`.
40
+ };
41
+ ```
42
+
43
+ ...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record<KeyType, unknown>`)...
44
+
45
+ ```
46
+ type RemoveIndexSignature<ObjectType> = {
47
+ [KeyType in keyof ObjectType
48
+ // Is `{}` assignable to `Record<KeyType, unknown>`?
49
+ as {} extends Record<KeyType, unknown>
50
+ ? ... // ✅ `{}` is assignable to `Record<KeyType, unknown>`
51
+ : ... // ❌ `{}` is NOT assignable to `Record<KeyType, unknown>`
52
+ ]: ObjectType[KeyType];
53
+ };
54
+ ```
55
+
56
+ If `{}` is assignable, it means that `KeyType` is an index signature and we want to remove it. If it is not assignable, `KeyType` is a "real" key and we want to keep it.
57
+
58
+ ```
59
+ type RemoveIndexSignature<ObjectType> = {
60
+ [KeyType in keyof ObjectType
61
+ as {} extends Record<KeyType, unknown>
62
+ ? never // => Remove this `KeyType`.
63
+ : KeyType // => Keep this `KeyType` as it is.
64
+ ]: ObjectType[KeyType];
65
+ };
66
+ ```
67
+
68
+ @example
69
+ ```
70
+ import {RemoveIndexSignature} from 'type-fest';
71
+
72
+ interface Example {
73
+ // These index signatures will be removed.
74
+ [x: string]: any
75
+ [x: number]: any
76
+ [x: symbol]: any
77
+ [x: `head-${string}`]: string
78
+ [x: `${string}-tail`]: string
79
+ [x: `head-${string}-tail`]: string
80
+ [x: `${bigint}`]: string
81
+ [x: `embedded-${number}`]: string
82
+
83
+ // These explicitly defined keys will remain.
84
+ foo: 'bar';
85
+ qux?: 'baz';
86
+ }
87
+
88
+ type ExampleWithoutIndexSignatures = RemoveIndexSignature<Example>;
89
+ // => { foo: 'bar'; qux?: 'baz' | undefined; }
90
+ ```
91
+
92
+ @category Object
93
+ */
94
+ export type RemoveIndexSignature<ObjectType> = {
95
+ [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
96
+ ? never
97
+ : KeyType]: ObjectType[KeyType];
98
+ };
@@ -0,0 +1,72 @@
1
+ /**
2
+ Create a deep version of another object type where property values are recursively replaced into a given value type.
3
+
4
+ Use-cases:
5
+ - Form validation: Define how each field should be validated.
6
+ - Form settings: Define configuration for input fields.
7
+ - Parsing: Define types that specify special behavior for specific fields.
8
+
9
+ @example
10
+ ```
11
+ import {Schema} from 'type-fest';
12
+
13
+ interface User {
14
+ id: string;
15
+ name: {
16
+ firstname: string;
17
+ lastname: string;
18
+ };
19
+ created: Date;
20
+ active: boolean;
21
+ passwordHash: string;
22
+ }
23
+
24
+ type UserMask = Schema<User, 'mask' | 'hide' | 'show'>;
25
+
26
+ const userMaskSettings: UserMask = {
27
+ id: 'show',
28
+ name: {
29
+ firstname: 'show',
30
+ lastname: 'mask',
31
+ },
32
+ phoneNumbers: 'mask',
33
+ created: 'show',
34
+ active: 'show',
35
+ passwordHash: 'hide',
36
+ }
37
+ ```
38
+
39
+ @category Object
40
+ */
41
+ export type Schema<ObjectType, ValueType> = ObjectType extends string
42
+ ? ValueType
43
+ : ObjectType extends Map<unknown, unknown>
44
+ ? ValueType
45
+ : ObjectType extends Set<unknown>
46
+ ? ValueType
47
+ : ObjectType extends ReadonlyMap<unknown, unknown>
48
+ ? ValueType
49
+ : ObjectType extends ReadonlySet<unknown>
50
+ ? ValueType
51
+ : ObjectType extends readonly unknown[]
52
+ ? ValueType
53
+ : ObjectType extends unknown[]
54
+ ? ValueType
55
+ : ObjectType extends (...arguments: unknown[]) => unknown
56
+ ? ValueType
57
+ : ObjectType extends Date
58
+ ? ValueType
59
+ : ObjectType extends Function
60
+ ? ValueType
61
+ : ObjectType extends RegExp
62
+ ? ValueType
63
+ : ObjectType extends object
64
+ ? SchemaObject<ObjectType, ValueType>
65
+ : ValueType;
66
+
67
+ /**
68
+ Same as `Schema`, but accepts only `object`s as inputs. Internal helper for `Schema`.
69
+ */
70
+ type SchemaObject<ObjectType extends object, K> = {
71
+ [KeyType in keyof ObjectType]: Schema<ObjectType[KeyType], K> | K;
72
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ Get keys of the given type as strings.
3
+
4
+ Number keys are converted to strings.
5
+
6
+ Use-cases:
7
+ - Get string keys from a type which may have number keys.
8
+ - Makes it possible to index using strings retrieved from template types.
9
+
10
+ @example
11
+ ```
12
+ import {StringKeyOf} from 'type-fest';
13
+
14
+ type Foo = {
15
+ 1: number,
16
+ stringKey: string,
17
+ };
18
+
19
+ type StringKeysOfFoo = StringKeyOf<Foo>;
20
+ //=> '1' | 'stringKey'
21
+ ```
22
+
23
+ @category Object
24
+ */
25
+ export type StringKeyOf<BaseType> = `${Extract<keyof BaseType, string | number>}`;