@visulima/object 1.0.6 → 1.0.8

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/dist/index.d.mts CHANGED
@@ -76,8 +76,8 @@ type Includes<Value extends readonly any[], Item> =
76
76
  @category Utilities
77
77
  */
78
78
  type IsEqual<A, B> =
79
- (<G>() => G extends A ? 1 : 2) extends
80
- (<G>() => G extends B ? 1 : 2)
79
+ (<G>() => G extends A & G | G ? 1 : 2) extends
80
+ (<G>() => G extends B & G | G ? 1 : 2)
81
81
  ? true
82
82
  : false;
83
83
 
@@ -166,6 +166,72 @@ fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface`
166
166
  */
167
167
  type Simplify<T> = {[KeyType in keyof T]: T[KeyType]} & {};
168
168
 
169
+ /**
170
+ Returns a boolean for whether the given type is `never`.
171
+
172
+ @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
173
+ @link https://stackoverflow.com/a/53984913/10292952
174
+ @link https://www.zhenghao.io/posts/ts-never
175
+
176
+ Useful in type utilities, such as checking if something does not occur.
177
+
178
+ @example
179
+ ```
180
+ import type {IsNever, And} from 'type-fest';
181
+
182
+ // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
183
+ type AreStringsEqual<A extends string, B extends string> =
184
+ And<
185
+ IsNever<Exclude<A, B>> extends true ? true : false,
186
+ IsNever<Exclude<B, A>> extends true ? true : false
187
+ >;
188
+
189
+ type EndIfEqual<I extends string, O extends string> =
190
+ AreStringsEqual<I, O> extends true
191
+ ? never
192
+ : void;
193
+
194
+ function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
195
+ if (input === output) {
196
+ process.exit(0);
197
+ }
198
+ }
199
+
200
+ endIfEqual('abc', 'abc');
201
+ //=> never
202
+
203
+ endIfEqual('abc', '123');
204
+ //=> void
205
+ ```
206
+
207
+ @category Type Guard
208
+ @category Utilities
209
+ */
210
+ type IsNever<T> = [T] extends [never] ? true : false;
211
+
212
+ /**
213
+ An if-else-like type that resolves depending on whether the given type is `never`.
214
+
215
+ @see {@link IsNever}
216
+
217
+ @example
218
+ ```
219
+ import type {IfNever} from 'type-fest';
220
+
221
+ type ShouldBeTrue = IfNever<never>;
222
+ //=> true
223
+
224
+ type ShouldBeBar = IfNever<'not never', 'foo', 'bar'>;
225
+ //=> 'bar'
226
+ ```
227
+
228
+ @category Type Guard
229
+ @category Utilities
230
+ */
231
+ type IfNever<T, TypeIfNever = true, TypeIfNotNever = false> = (
232
+ IsNever<T> extends true ? TypeIfNever : TypeIfNotNever
233
+ );
234
+
169
235
  /**
170
236
  Returns the static, fixed-length portion of the given array, excluding variable-length parts.
171
237
 
@@ -227,10 +293,14 @@ T extends readonly [...infer U] ?
227
293
  /**
228
294
  Returns whether the given array `T` is readonly.
229
295
  */
230
- type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
296
+ type IsArrayReadonly<T extends UnknownArray> = IfNever<T, false, T extends unknown[] ? false : true>;
231
297
 
232
298
  type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
233
299
 
300
+ // Can eventually be replaced with the built-in once this library supports
301
+ // TS5.4+ only. Tracked in https://github.com/sindresorhus/type-fest/issues/848
302
+ type NoInfer<T> = T extends infer U ? U : never;
303
+
234
304
  /**
235
305
  Returns a boolean for whether the given type is `any`.
236
306
 
@@ -259,7 +329,7 @@ const anyA = get(anyObject, 'a');
259
329
  @category Type Guard
260
330
  @category Utilities
261
331
  */
262
- type IsAny<T> = 0 extends 1 & T ? true : false;
332
+ type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
263
333
 
264
334
  type Numeric = number | bigint;
265
335
 
@@ -320,49 +390,6 @@ type ShouldBeTrue = IsNegative<-1>;
320
390
  */
321
391
  type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
322
392
 
323
- /**
324
- Returns a boolean for whether the given type is `never`.
325
-
326
- @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
327
- @link https://stackoverflow.com/a/53984913/10292952
328
- @link https://www.zhenghao.io/posts/ts-never
329
-
330
- Useful in type utilities, such as checking if something does not occur.
331
-
332
- @example
333
- ```
334
- import type {IsNever, And} from 'type-fest';
335
-
336
- // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
337
- type AreStringsEqual<A extends string, B extends string> =
338
- And<
339
- IsNever<Exclude<A, B>> extends true ? true : false,
340
- IsNever<Exclude<B, A>> extends true ? true : false
341
- >;
342
-
343
- type EndIfEqual<I extends string, O extends string> =
344
- AreStringsEqual<I, O> extends true
345
- ? never
346
- : void;
347
-
348
- function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
349
- if (input === output) {
350
- process.exit(0);
351
- }
352
- }
353
-
354
- endIfEqual('abc', 'abc');
355
- //=> never
356
-
357
- endIfEqual('abc', '123');
358
- //=> void
359
- ```
360
-
361
- @category Type Guard
362
- @category Utilities
363
- */
364
- type IsNever<T> = [T] extends [never] ? true : false;
365
-
366
393
  /**
367
394
  Returns a boolean for whether two given types are both true.
368
395
 
@@ -866,41 +893,6 @@ Matches non-recursive types.
866
893
  */
867
894
  type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
868
895
 
869
- /**
870
- Returns a boolean for whether the given type is a union type.
871
-
872
- @example
873
- ```
874
- type A = IsUnion<string | number>;
875
- //=> true
876
-
877
- type B = IsUnion<string>;
878
- //=> false
879
- ```
880
- */
881
- type IsUnion<T> = InternalIsUnion<T>;
882
-
883
- /**
884
- The actual implementation of `IsUnion`.
885
- */
886
- type InternalIsUnion<T, U = T> =
887
- (
888
- // @link https://ghaiklor.github.io/type-challenges-solutions/en/medium-isunion.html
889
- IsNever<T> extends true
890
- ? false
891
- : T extends any
892
- ? [U] extends [T]
893
- ? false
894
- : true
895
- : never
896
- ) extends infer Result
897
- // In some cases `Result` will return `false | true` which is `boolean`,
898
- // that means `T` has at least two types and it's a union type,
899
- // so we will return `true` instead of `boolean`.
900
- ? boolean extends Result ? true
901
- : Result
902
- : never; // Should never happen
903
-
904
896
  /**
905
897
  Create an object type with the given key `<Key>` and value `<Value>`.
906
898
 
@@ -1725,13 +1717,13 @@ type Dog = {
1725
1717
  function displayPetInfo(petInfo: (Cat | Dog)['info']) {
1726
1718
  // typeof petInfo =>
1727
1719
  // {
1728
- // name: string;
1729
- // type: 'cat';
1730
- // catType: string; // Needn't care about this field, because it's not a common pet info field.
1720
+ // name: string;
1721
+ // type: 'cat';
1722
+ // catType: string; // Needn't care about this field, because it's not a common pet info field.
1731
1723
  // } | {
1732
- // name: string;
1733
- // type: 'dog';
1734
- // dogType: string; // Needn't care about this field, because it's not a common pet info field.
1724
+ // name: string;
1725
+ // type: 'dog';
1726
+ // dogType: string; // Needn't care about this field, because it's not a common pet info field.
1735
1727
  // }
1736
1728
 
1737
1729
  // petInfo type is complex and have some needless fields
@@ -1743,8 +1735,8 @@ function displayPetInfo(petInfo: (Cat | Dog)['info']) {
1743
1735
  function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
1744
1736
  // typeof petInfo =>
1745
1737
  // {
1746
- // name: string;
1747
- // type: 'cat' | 'dog';
1738
+ // name: string;
1739
+ // type: 'cat' | 'dog';
1748
1740
  // }
1749
1741
 
1750
1742
  // petInfo type is simple and clear
@@ -1754,17 +1746,16 @@ function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
1754
1746
  }
1755
1747
  ```
1756
1748
 
1749
+ @see SharedUnionFields
1750
+
1757
1751
  @category Object
1758
1752
  @category Union
1759
1753
  */
1760
1754
  type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
1761
- // If `Union` is not a union type, return `Union` directly.
1762
- IsUnion<Union> extends false
1763
- ? Union
1764
1755
  // `Union extends` will convert `Union`
1765
1756
  // to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
1766
1757
  // But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
1767
- : [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
1758
+ [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
1768
1759
  ? Union
1769
1760
  : [Union] extends [UnknownArray]
1770
1761
  ? Options['recurseIntoArrays'] extends true
@@ -1778,13 +1769,18 @@ IsUnion<Union> extends false
1778
1769
  Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
1779
1770
  */
1780
1771
  type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
1772
+ // `keyof Union` can extract the same key in union type, if there is no same key, return never.
1781
1773
  keyof Union extends infer Keys
1782
1774
  ? IsNever<Keys> extends false
1783
1775
  ? {
1784
1776
  [Key in keyof Union]:
1785
1777
  Union[Key] extends NonRecursiveType
1786
1778
  ? Union[Key]
1787
- : SharedUnionFieldsDeep<Union[Key], Options>
1779
+ // Remove `undefined` from the union to support optional
1780
+ // fields, then recover `undefined` if union was already undefined.
1781
+ : SharedUnionFieldsDeep<Exclude<Union[Key], undefined>, Options> | (
1782
+ undefined extends Required<Union>[Key] ? undefined : never
1783
+ )
1788
1784
  }
1789
1785
  : {}
1790
1786
  : Union;
@@ -2173,8 +2169,20 @@ type PropertyOf<BaseType, Key extends string, Options extends GetOptions = {}> =
2173
2169
  ? undefined
2174
2170
  : Key extends keyof BaseType
2175
2171
  ? StrictPropertyOf<BaseType, Key, Options>
2176
- : BaseType extends readonly [] | readonly [unknown, ...unknown[]]
2177
- ? unknown // It's a tuple, but `Key` did not extend `keyof BaseType`. So the index is out of bounds.
2172
+ // Handle arrays and tuples
2173
+ : BaseType extends readonly unknown[]
2174
+ ? Key extends `${number}`
2175
+ // For arrays with unknown length (regular arrays)
2176
+ ? number extends BaseType['length']
2177
+ ? Strictify<BaseType[number], Options>
2178
+ // For tuples: check if the index is valid
2179
+ : Key extends keyof BaseType
2180
+ ? Strictify<BaseType[Key & keyof BaseType], Options>
2181
+ // Out-of-bounds access for tuples
2182
+ : unknown
2183
+ // Non-numeric string key for arrays/tuples
2184
+ : unknown
2185
+ // Handle array-like objects
2178
2186
  : BaseType extends {
2179
2187
  [n: number]: infer Item;
2180
2188
  length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.
package/dist/index.d.ts CHANGED
@@ -76,8 +76,8 @@ type Includes<Value extends readonly any[], Item> =
76
76
  @category Utilities
77
77
  */
78
78
  type IsEqual<A, B> =
79
- (<G>() => G extends A ? 1 : 2) extends
80
- (<G>() => G extends B ? 1 : 2)
79
+ (<G>() => G extends A & G | G ? 1 : 2) extends
80
+ (<G>() => G extends B & G | G ? 1 : 2)
81
81
  ? true
82
82
  : false;
83
83
 
@@ -166,6 +166,72 @@ fn(someInterface as Simplify<SomeInterface>); // Good: transform an `interface`
166
166
  */
167
167
  type Simplify<T> = {[KeyType in keyof T]: T[KeyType]} & {};
168
168
 
169
+ /**
170
+ Returns a boolean for whether the given type is `never`.
171
+
172
+ @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
173
+ @link https://stackoverflow.com/a/53984913/10292952
174
+ @link https://www.zhenghao.io/posts/ts-never
175
+
176
+ Useful in type utilities, such as checking if something does not occur.
177
+
178
+ @example
179
+ ```
180
+ import type {IsNever, And} from 'type-fest';
181
+
182
+ // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
183
+ type AreStringsEqual<A extends string, B extends string> =
184
+ And<
185
+ IsNever<Exclude<A, B>> extends true ? true : false,
186
+ IsNever<Exclude<B, A>> extends true ? true : false
187
+ >;
188
+
189
+ type EndIfEqual<I extends string, O extends string> =
190
+ AreStringsEqual<I, O> extends true
191
+ ? never
192
+ : void;
193
+
194
+ function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
195
+ if (input === output) {
196
+ process.exit(0);
197
+ }
198
+ }
199
+
200
+ endIfEqual('abc', 'abc');
201
+ //=> never
202
+
203
+ endIfEqual('abc', '123');
204
+ //=> void
205
+ ```
206
+
207
+ @category Type Guard
208
+ @category Utilities
209
+ */
210
+ type IsNever<T> = [T] extends [never] ? true : false;
211
+
212
+ /**
213
+ An if-else-like type that resolves depending on whether the given type is `never`.
214
+
215
+ @see {@link IsNever}
216
+
217
+ @example
218
+ ```
219
+ import type {IfNever} from 'type-fest';
220
+
221
+ type ShouldBeTrue = IfNever<never>;
222
+ //=> true
223
+
224
+ type ShouldBeBar = IfNever<'not never', 'foo', 'bar'>;
225
+ //=> 'bar'
226
+ ```
227
+
228
+ @category Type Guard
229
+ @category Utilities
230
+ */
231
+ type IfNever<T, TypeIfNever = true, TypeIfNotNever = false> = (
232
+ IsNever<T> extends true ? TypeIfNever : TypeIfNotNever
233
+ );
234
+
169
235
  /**
170
236
  Returns the static, fixed-length portion of the given array, excluding variable-length parts.
171
237
 
@@ -227,10 +293,14 @@ T extends readonly [...infer U] ?
227
293
  /**
228
294
  Returns whether the given array `T` is readonly.
229
295
  */
230
- type IsArrayReadonly<T extends UnknownArray> = T extends unknown[] ? false : true;
296
+ type IsArrayReadonly<T extends UnknownArray> = IfNever<T, false, T extends unknown[] ? false : true>;
231
297
 
232
298
  type StringDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
233
299
 
300
+ // Can eventually be replaced with the built-in once this library supports
301
+ // TS5.4+ only. Tracked in https://github.com/sindresorhus/type-fest/issues/848
302
+ type NoInfer<T> = T extends infer U ? U : never;
303
+
234
304
  /**
235
305
  Returns a boolean for whether the given type is `any`.
236
306
 
@@ -259,7 +329,7 @@ const anyA = get(anyObject, 'a');
259
329
  @category Type Guard
260
330
  @category Utilities
261
331
  */
262
- type IsAny<T> = 0 extends 1 & T ? true : false;
332
+ type IsAny<T> = 0 extends 1 & NoInfer<T> ? true : false;
263
333
 
264
334
  type Numeric = number | bigint;
265
335
 
@@ -320,49 +390,6 @@ type ShouldBeTrue = IsNegative<-1>;
320
390
  */
321
391
  type IsNegative<T extends Numeric> = T extends Negative<T> ? true : false;
322
392
 
323
- /**
324
- Returns a boolean for whether the given type is `never`.
325
-
326
- @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
327
- @link https://stackoverflow.com/a/53984913/10292952
328
- @link https://www.zhenghao.io/posts/ts-never
329
-
330
- Useful in type utilities, such as checking if something does not occur.
331
-
332
- @example
333
- ```
334
- import type {IsNever, And} from 'type-fest';
335
-
336
- // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
337
- type AreStringsEqual<A extends string, B extends string> =
338
- And<
339
- IsNever<Exclude<A, B>> extends true ? true : false,
340
- IsNever<Exclude<B, A>> extends true ? true : false
341
- >;
342
-
343
- type EndIfEqual<I extends string, O extends string> =
344
- AreStringsEqual<I, O> extends true
345
- ? never
346
- : void;
347
-
348
- function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
349
- if (input === output) {
350
- process.exit(0);
351
- }
352
- }
353
-
354
- endIfEqual('abc', 'abc');
355
- //=> never
356
-
357
- endIfEqual('abc', '123');
358
- //=> void
359
- ```
360
-
361
- @category Type Guard
362
- @category Utilities
363
- */
364
- type IsNever<T> = [T] extends [never] ? true : false;
365
-
366
393
  /**
367
394
  Returns a boolean for whether two given types are both true.
368
395
 
@@ -866,41 +893,6 @@ Matches non-recursive types.
866
893
  */
867
894
  type NonRecursiveType = BuiltIns | Function | (new (...arguments_: any[]) => unknown);
868
895
 
869
- /**
870
- Returns a boolean for whether the given type is a union type.
871
-
872
- @example
873
- ```
874
- type A = IsUnion<string | number>;
875
- //=> true
876
-
877
- type B = IsUnion<string>;
878
- //=> false
879
- ```
880
- */
881
- type IsUnion<T> = InternalIsUnion<T>;
882
-
883
- /**
884
- The actual implementation of `IsUnion`.
885
- */
886
- type InternalIsUnion<T, U = T> =
887
- (
888
- // @link https://ghaiklor.github.io/type-challenges-solutions/en/medium-isunion.html
889
- IsNever<T> extends true
890
- ? false
891
- : T extends any
892
- ? [U] extends [T]
893
- ? false
894
- : true
895
- : never
896
- ) extends infer Result
897
- // In some cases `Result` will return `false | true` which is `boolean`,
898
- // that means `T` has at least two types and it's a union type,
899
- // so we will return `true` instead of `boolean`.
900
- ? boolean extends Result ? true
901
- : Result
902
- : never; // Should never happen
903
-
904
896
  /**
905
897
  Create an object type with the given key `<Key>` and value `<Value>`.
906
898
 
@@ -1725,13 +1717,13 @@ type Dog = {
1725
1717
  function displayPetInfo(petInfo: (Cat | Dog)['info']) {
1726
1718
  // typeof petInfo =>
1727
1719
  // {
1728
- // name: string;
1729
- // type: 'cat';
1730
- // catType: string; // Needn't care about this field, because it's not a common pet info field.
1720
+ // name: string;
1721
+ // type: 'cat';
1722
+ // catType: string; // Needn't care about this field, because it's not a common pet info field.
1731
1723
  // } | {
1732
- // name: string;
1733
- // type: 'dog';
1734
- // dogType: string; // Needn't care about this field, because it's not a common pet info field.
1724
+ // name: string;
1725
+ // type: 'dog';
1726
+ // dogType: string; // Needn't care about this field, because it's not a common pet info field.
1735
1727
  // }
1736
1728
 
1737
1729
  // petInfo type is complex and have some needless fields
@@ -1743,8 +1735,8 @@ function displayPetInfo(petInfo: (Cat | Dog)['info']) {
1743
1735
  function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
1744
1736
  // typeof petInfo =>
1745
1737
  // {
1746
- // name: string;
1747
- // type: 'cat' | 'dog';
1738
+ // name: string;
1739
+ // type: 'cat' | 'dog';
1748
1740
  // }
1749
1741
 
1750
1742
  // petInfo type is simple and clear
@@ -1754,17 +1746,16 @@ function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
1754
1746
  }
1755
1747
  ```
1756
1748
 
1749
+ @see SharedUnionFields
1750
+
1757
1751
  @category Object
1758
1752
  @category Union
1759
1753
  */
1760
1754
  type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
1761
- // If `Union` is not a union type, return `Union` directly.
1762
- IsUnion<Union> extends false
1763
- ? Union
1764
1755
  // `Union extends` will convert `Union`
1765
1756
  // to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
1766
1757
  // But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
1767
- : [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
1758
+ [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
1768
1759
  ? Union
1769
1760
  : [Union] extends [UnknownArray]
1770
1761
  ? Options['recurseIntoArrays'] extends true
@@ -1778,13 +1769,18 @@ IsUnion<Union> extends false
1778
1769
  Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
1779
1770
  */
1780
1771
  type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
1772
+ // `keyof Union` can extract the same key in union type, if there is no same key, return never.
1781
1773
  keyof Union extends infer Keys
1782
1774
  ? IsNever<Keys> extends false
1783
1775
  ? {
1784
1776
  [Key in keyof Union]:
1785
1777
  Union[Key] extends NonRecursiveType
1786
1778
  ? Union[Key]
1787
- : SharedUnionFieldsDeep<Union[Key], Options>
1779
+ // Remove `undefined` from the union to support optional
1780
+ // fields, then recover `undefined` if union was already undefined.
1781
+ : SharedUnionFieldsDeep<Exclude<Union[Key], undefined>, Options> | (
1782
+ undefined extends Required<Union>[Key] ? undefined : never
1783
+ )
1788
1784
  }
1789
1785
  : {}
1790
1786
  : Union;
@@ -2173,8 +2169,20 @@ type PropertyOf<BaseType, Key extends string, Options extends GetOptions = {}> =
2173
2169
  ? undefined
2174
2170
  : Key extends keyof BaseType
2175
2171
  ? StrictPropertyOf<BaseType, Key, Options>
2176
- : BaseType extends readonly [] | readonly [unknown, ...unknown[]]
2177
- ? unknown // It's a tuple, but `Key` did not extend `keyof BaseType`. So the index is out of bounds.
2172
+ // Handle arrays and tuples
2173
+ : BaseType extends readonly unknown[]
2174
+ ? Key extends `${number}`
2175
+ // For arrays with unknown length (regular arrays)
2176
+ ? number extends BaseType['length']
2177
+ ? Strictify<BaseType[number], Options>
2178
+ // For tuples: check if the index is valid
2179
+ : Key extends keyof BaseType
2180
+ ? Strictify<BaseType[Key & keyof BaseType], Options>
2181
+ // Out-of-bounds access for tuples
2182
+ : unknown
2183
+ // Non-numeric string key for arrays/tuples
2184
+ : unknown
2185
+ // Handle array-like objects
2178
2186
  : BaseType extends {
2179
2187
  [n: number]: infer Item;
2180
2188
  length: number; // Note: This is needed to avoid being too lax with records types using number keys like `{0: string; 1: boolean}`.