@shopify/hydrogen 2025.10.1 → 2026.1.1

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.
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ComponentType, ScriptHTMLAttributes, FC, ForwardRefExoticComponent, RefAttributes, ComponentProps } from 'react';
3
- import { BuyerInput, CountryCode as CountryCode$1, LanguageCode as LanguageCode$1, VisitorConsent as VisitorConsent$1, CartInput, CartLineInput, CartLineUpdateInput, CartBuyerIdentityInput, CartSelectedDeliveryOptionInput, AttributeInput, Scalars, CartSelectableAddressInput, CartSelectableAddressUpdateInput, Cart, CartMetafieldsSetInput, CartUserError, MetafieldsSetUserError, MetafieldDeleteUserError, CartWarning, Product, ProductVariant, CartLine, ComponentizableCartLine, CurrencyCode, PageInfo, Maybe, ProductOptionValue, SelectedOptionInput, ProductOption, ProductVariantConnection } from '@shopify/hydrogen-react/storefront-api-types';
3
+ import { BuyerInput, CountryCode as CountryCode$1, LanguageCode as LanguageCode$1, VisitorConsent as VisitorConsent$1, CartInput, CartLineInput, CartLineUpdateInput, CartBuyerIdentityInput, CartSelectedDeliveryOptionInput, AttributeInput, Scalars, CartSelectableAddressInput, CartSelectableAddressUpdateInput, Cart, CartMetafieldsSetInput, CartUserError, MetafieldsSetUserError, MetafieldDeleteUserError, CartWarning, Product, ProductVariant, CartLine, ComponentizableCartLine, CurrencyCode, PageInfo, Maybe, ProductOptionValue, ProductOption, ProductVariantConnection, SelectedOptionInput } from '@shopify/hydrogen-react/storefront-api-types';
4
4
  import { createStorefrontClient as createStorefrontClient$1, StorefrontClientProps, RichText as RichText$1, ShopPayButton as ShopPayButton$1 } from '@shopify/hydrogen-react';
5
5
  export { AnalyticsEventName, AnalyticsPageType, ClientBrowserParameters, ExternalVideo, IMAGE_FRAGMENT, Image, MappedProductOptions, MediaFile, ModelViewer, Money, ParsedMetafields, ShopifyAnalytics as SendShopifyAnalyticsEvent, ShopifyAddToCart, ShopifyAddToCartPayload, ShopifyAnalyticsPayload, ShopifyAnalyticsProduct, ShopifyCookies, ShopifyPageView, ShopifyPageViewPayload, ShopifySalesChannel, StorefrontApiResponse, StorefrontApiResponseError, StorefrontApiResponseOk, StorefrontApiResponseOkPartial, StorefrontApiResponsePartial, Video, customerAccountApiCustomScalars, decodeEncodedVariant, flattenConnection, getAdjacentAndFirstAvailableVariants, getClientBrowserParameters, getProductOptions, getShopifyCookies, getTrackingValues, isOptionValueCombinationInEncodedVariant, mapSelectedProductOptionToObject, parseGid, parseMetafield, sendShopifyAnalytics, storefrontApiCustomScalars, useLoadScript, useMoney, useSelectedOptionInUrlParam, useShopifyCookies } from '@shopify/hydrogen-react';
6
6
  import { LanguageCode, CountryCode } from '@shopify/hydrogen-react/customer-account-api-types';
@@ -158,128 +158,192 @@ type KeysOfUnion<ObjectType> =
158
158
  // Hack to fix https://github.com/sindresorhus/type-fest/issues/1008
159
159
  keyof UnionToIntersection<ObjectType extends unknown ? Record<keyof ObjectType, never> : never>;
160
160
  /**
161
- Returns a boolean for whether the two given types are equal.
162
-
163
- @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
164
- @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
161
+ Extract all optional keys from the given type.
165
162
 
166
- Use-cases:
167
- - If you want to make a conditional branch based on the result of a comparison of two types.
163
+ This is useful when you want to create a new type that contains different type values for the optional keys only.
168
164
 
169
165
  @example
170
166
  ```
171
- import type {IsEqual} from 'type-fest';
167
+ import type {OptionalKeysOf, Except} from 'type-fest';
172
168
 
173
- // This type returns a boolean for whether the given array includes the given item.
174
- // `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
175
- type Includes<Value extends readonly any[], Item> =
176
- Value extends readonly [Value[0], ...infer rest]
177
- ? IsEqual<Value[0], Item> extends true
178
- ? true
179
- : Includes<rest, Item>
180
- : false;
169
+ interface User {
170
+ name: string;
171
+ surname: string;
172
+
173
+ luckyNumber?: number;
174
+ }
175
+
176
+ const REMOVE_FIELD = Symbol('remove field symbol');
177
+ type UpdateOperation<Entity extends object> = Except<Partial<Entity>, OptionalKeysOf<Entity>> & {
178
+ [Key in OptionalKeysOf<Entity>]?: Entity[Key] | typeof REMOVE_FIELD;
179
+ };
180
+
181
+ const update1: UpdateOperation<User> = {
182
+ name: 'Alice'
183
+ };
184
+
185
+ const update2: UpdateOperation<User> = {
186
+ name: 'Bob',
187
+ luckyNumber: REMOVE_FIELD
188
+ };
181
189
  ```
182
190
 
183
- @category Type Guard
184
191
  @category Utilities
185
192
  */
186
- type IsEqual<A, B> = (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2) ? true : false;
193
+ type OptionalKeysOf<BaseType extends object> = BaseType extends unknown // For distributing `BaseType`
194
+ ? (keyof {
195
+ [Key in keyof BaseType as BaseType extends Record<Key, BaseType[Key]> ? never : Key]: never;
196
+ }) & (keyof BaseType) // Intersect with `keyof BaseType` to ensure result of `OptionalKeysOf<BaseType>` is always assignable to `keyof BaseType`
197
+ : never; // Should never happen
187
198
  /**
188
- Filter out keys from an object.
199
+ Extract all required keys from the given type.
189
200
 
190
- Returns `never` if `Exclude` is strictly equal to `Key`.
191
- Returns `never` if `Key` extends `Exclude`.
192
- Returns `Key` otherwise.
201
+ This is useful when you want to create a new type that contains different type values for the required keys only or use the list of keys for validation purposes, etc...
193
202
 
194
203
  @example
195
204
  ```
196
- type Filtered = Filter<'foo', 'foo'>;
197
- //=> never
205
+ import type {RequiredKeysOf} from 'type-fest';
206
+
207
+ declare function createValidation<Entity extends object, Key extends RequiredKeysOf<Entity> = RequiredKeysOf<Entity>>(field: Key, validator: (value: Entity[Key]) => boolean): ValidatorFn;
208
+
209
+ interface User {
210
+ name: string;
211
+ surname: string;
212
+
213
+ luckyNumber?: number;
214
+ }
215
+
216
+ const validator1 = createValidation<User>('name', value => value.length < 25);
217
+ const validator2 = createValidation<User>('surname', value => value.length < 25);
198
218
  ```
199
219
 
220
+ @category Utilities
221
+ */
222
+ type RequiredKeysOf<BaseType extends object> = BaseType extends unknown // For distributing `BaseType`
223
+ ? Exclude<keyof BaseType, OptionalKeysOf<BaseType>> : never; // Should never happen
224
+ /**
225
+ Returns a boolean for whether the given type is `never`.
226
+
227
+ @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
228
+ @link https://stackoverflow.com/a/53984913/10292952
229
+ @link https://www.zhenghao.io/posts/ts-never
230
+
231
+ Useful in type utilities, such as checking if something does not occur.
232
+
200
233
  @example
201
234
  ```
202
- type Filtered = Filter<'bar', string>;
235
+ import type {IsNever, And} from 'type-fest';
236
+
237
+ // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
238
+ type AreStringsEqual<A extends string, B extends string> =
239
+ And<
240
+ IsNever<Exclude<A, B>> extends true ? true : false,
241
+ IsNever<Exclude<B, A>> extends true ? true : false
242
+ >;
243
+
244
+ type EndIfEqual<I extends string, O extends string> =
245
+ AreStringsEqual<I, O> extends true
246
+ ? never
247
+ : void;
248
+
249
+ function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
250
+ if (input === output) {
251
+ process.exit(0);
252
+ }
253
+ }
254
+
255
+ endIfEqual('abc', 'abc');
203
256
  //=> never
257
+
258
+ endIfEqual('abc', '123');
259
+ //=> void
204
260
  ```
205
261
 
262
+ @category Type Guard
263
+ @category Utilities
264
+ */
265
+ type IsNever<T> = [
266
+ T
267
+ ] extends [
268
+ never
269
+ ] ? true : false;
270
+ /**
271
+ An if-else-like type that resolves depending on whether the given type is `never`.
272
+
273
+ @see {@link IsNever}
274
+
206
275
  @example
207
276
  ```
208
- type Filtered = Filter<'bar', 'foo'>;
277
+ import type {IfNever} from 'type-fest';
278
+
279
+ type ShouldBeTrue = IfNever<never>;
280
+ //=> true
281
+
282
+ type ShouldBeBar = IfNever<'not never', 'foo', 'bar'>;
209
283
  //=> 'bar'
210
284
  ```
211
285
 
212
- @see {Except}
286
+ @category Type Guard
287
+ @category Utilities
213
288
  */
214
- type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
215
- type ExceptOptions = {
216
- /**
217
- Disallow assigning non-specified properties.
218
-
219
- Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`.
220
-
221
- @default false
222
- */
223
- requireExactProps?: boolean;
224
- };
289
+ type IfNever<T, TypeIfNever = true, TypeIfNotNever = false> = (IsNever<T> extends true ? TypeIfNever : TypeIfNotNever);
290
+ type NoInfer$1<T> = T extends infer U ? U : never;
225
291
  /**
226
- Create a type from an object type without certain keys.
227
-
228
- We recommend setting the `requireExactProps` option to `true`.
292
+ Returns a boolean for whether the given type is `any`.
229
293
 
230
- 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.
294
+ @link https://stackoverflow.com/a/49928360/1490091
231
295
 
232
- 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)).
296
+ Useful in type utilities, such as disallowing `any`s to be passed to a function.
233
297
 
234
298
  @example
235
299
  ```
236
- import type {Except} from 'type-fest';
237
-
238
- type Foo = {
239
- a: number;
240
- b: string;
241
- };
300
+ import type {IsAny} from 'type-fest';
242
301
 
243
- type FooWithoutA = Except<Foo, 'a'>;
244
- //=> {b: string}
302
+ const typedObject = {a: 1, b: 2} as const;
303
+ const anyObject: any = {a: 1, b: 2};
245
304
 
246
- const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
247
- //=> errors: 'a' does not exist in type '{ b: string; }'
305
+ function get<O extends (IsAny<O> extends true ? {} : Record<string, number>), K extends keyof O = keyof O>(obj: O, key: K) {
306
+ return obj[key];
307
+ }
248
308
 
249
- type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
250
- //=> {a: number} & Partial<Record<"b", never>>
309
+ const typedA = get(typedObject, 'a');
310
+ //=> 1
251
311
 
252
- const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
253
- //=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
312
+ const anyA = get(anyObject, 'a');
313
+ //=> any
314
+ ```
254
315
 
255
- // The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures.
316
+ @category Type Guard
317
+ @category Utilities
318
+ */
319
+ type IsAny<T> = 0 extends 1 & NoInfer$1<T> ? true : false;
320
+ /**
321
+ Returns a boolean for whether the two given types are equal.
256
322
 
257
- // Consider the following example:
323
+ @link https://github.com/microsoft/TypeScript/issues/27024#issuecomment-421529650
324
+ @link https://stackoverflow.com/questions/68961864/how-does-the-equals-work-in-typescript/68963796#68963796
258
325
 
259
- type UserData = {
260
- [metadata: string]: string;
261
- email: string;
262
- name: string;
263
- role: 'admin' | 'user';
264
- };
326
+ Use-cases:
327
+ - If you want to make a conditional branch based on the result of a comparison of two types.
265
328
 
266
- // `Omit` clearly doesn't behave as expected in this case:
267
- type PostPayload = Omit<UserData, 'email'>;
268
- //=> type PostPayload = { [x: string]: string; [x: number]: string; }
329
+ @example
330
+ ```
331
+ import type {IsEqual} from 'type-fest';
269
332
 
270
- // In situations like this, `Except` works better.
271
- // It simply removes the `email` key while preserving all the other keys.
272
- type PostPayload = Except<UserData, 'email'>;
273
- //=> type PostPayload = { [x: string]: string; name: string; role: 'admin' | 'user'; }
333
+ // This type returns a boolean for whether the given array includes the given item.
334
+ // `IsEqual` is used to compare the given array at position 0 and the given item and then return true if they are equal.
335
+ type Includes<Value extends readonly any[], Item> =
336
+ Value extends readonly [Value[0], ...infer rest]
337
+ ? IsEqual<Value[0], Item> extends true
338
+ ? true
339
+ : Includes<rest, Item>
340
+ : false;
274
341
  ```
275
342
 
276
- @category Object
343
+ @category Type Guard
344
+ @category Utilities
277
345
  */
278
- type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {
279
- requireExactProps: false;
280
- }> = {
281
- [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
282
- } & (Options["requireExactProps"] extends true ? Partial<Record<KeysType, never>> : {});
346
+ type IsEqual<A, B> = (<G>() => G extends A & G | G ? 1 : 2) extends (<G>() => G extends B & G | G ? 1 : 2) ? true : false;
283
347
  /**
284
348
  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.
285
349
 
@@ -341,51 +405,205 @@ type Simplify<T> = {
341
405
  [KeyType in keyof T]: T[KeyType];
342
406
  } & {};
343
407
  /**
344
- Returns a boolean for whether the given type is `never`.
408
+ Omit any index signatures from the given object type, leaving only explicitly defined properties.
345
409
 
346
- @link https://github.com/microsoft/TypeScript/issues/31751#issuecomment-498526919
347
- @link https://stackoverflow.com/a/53984913/10292952
348
- @link https://www.zhenghao.io/posts/ts-never
410
+ This is the counterpart of `PickIndexSignature`.
349
411
 
350
- Useful in type utilities, such as checking if something does not occur.
412
+ Use-cases:
413
+ - Remove overly permissive signatures from third-party types.
414
+
415
+ This type was taken from this [StackOverflow answer](https://stackoverflow.com/a/68261113/420747).
416
+
417
+ 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>`.
418
+
419
+ (The actual value type, `unknown`, is irrelevant and could be any type. Only the key type matters.)
420
+
421
+ ```
422
+ const indexed: Record<string, unknown> = {}; // Allowed
423
+
424
+ const keyed: Record<'foo', unknown> = {}; // Error
425
+ // => TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
426
+ ```
427
+
428
+ 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:
429
+
430
+ ```
431
+ type Indexed = {} extends Record<string, unknown>
432
+ ? '✅ `{}` is assignable to `Record<string, unknown>`'
433
+ : '❌ `{}` is NOT assignable to `Record<string, unknown>`';
434
+ // => '✅ `{}` is assignable to `Record<string, unknown>`'
435
+
436
+ type Keyed = {} extends Record<'foo' | 'bar', unknown>
437
+ ? "✅ `{}` is assignable to `Record<'foo' | 'bar', unknown>`"
438
+ : "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`";
439
+ // => "❌ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`"
440
+ ```
441
+
442
+ 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`...
443
+
444
+ ```
445
+ import type {OmitIndexSignature} from 'type-fest';
446
+
447
+ type OmitIndexSignature<ObjectType> = {
448
+ [KeyType in keyof ObjectType // Map each key of `ObjectType`...
449
+ ]: ObjectType[KeyType]; // ...to its original value, i.e. `OmitIndexSignature<Foo> == Foo`.
450
+ };
451
+ ```
452
+
453
+ ...whether an empty object (`{}`) would be assignable to an object with that `KeyType` (`Record<KeyType, unknown>`)...
454
+
455
+ ```
456
+ import type {OmitIndexSignature} from 'type-fest';
457
+
458
+ type OmitIndexSignature<ObjectType> = {
459
+ [KeyType in keyof ObjectType
460
+ // Is `{}` assignable to `Record<KeyType, unknown>`?
461
+ as {} extends Record<KeyType, unknown>
462
+ ? ... // ✅ `{}` is assignable to `Record<KeyType, unknown>`
463
+ : ... // ❌ `{}` is NOT assignable to `Record<KeyType, unknown>`
464
+ ]: ObjectType[KeyType];
465
+ };
466
+ ```
467
+
468
+ 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.
351
469
 
352
470
  @example
353
471
  ```
354
- import type {IsNever, And} from 'type-fest';
472
+ import type {OmitIndexSignature} from 'type-fest';
473
+
474
+ interface Example {
475
+ // These index signatures will be removed.
476
+ [x: string]: any
477
+ [x: number]: any
478
+ [x: symbol]: any
479
+ [x: `head-${string}`]: string
480
+ [x: `${string}-tail`]: string
481
+ [x: `head-${string}-tail`]: string
482
+ [x: `${bigint}`]: string
483
+ [x: `embedded-${number}`]: string
484
+
485
+ // These explicitly defined keys will remain.
486
+ foo: 'bar';
487
+ qux?: 'baz';
488
+ }
355
489
 
356
- // https://github.com/andnp/SimplyTyped/blob/master/src/types/strings.ts
357
- type AreStringsEqual<A extends string, B extends string> =
358
- And<
359
- IsNever<Exclude<A, B>> extends true ? true : false,
360
- IsNever<Exclude<B, A>> extends true ? true : false
361
- >;
490
+ type ExampleWithoutIndexSignatures = OmitIndexSignature<Example>;
491
+ // => { foo: 'bar'; qux?: 'baz' | undefined; }
492
+ ```
362
493
 
363
- type EndIfEqual<I extends string, O extends string> =
364
- AreStringsEqual<I, O> extends true
365
- ? never
366
- : void;
494
+ @see PickIndexSignature
495
+ @category Object
496
+ */
497
+ type OmitIndexSignature<ObjectType> = {
498
+ [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? never : KeyType]: ObjectType[KeyType];
499
+ };
500
+ /**
501
+ Pick only index signatures from the given object type, leaving out all explicitly defined properties.
367
502
 
368
- function endIfEqual<I extends string, O extends string>(input: I, output: O): EndIfEqual<I, O> {
369
- if (input === output) {
370
- process.exit(0);
371
- }
503
+ This is the counterpart of `OmitIndexSignature`.
504
+
505
+ @example
506
+ ```
507
+ import type {PickIndexSignature} from 'type-fest';
508
+
509
+ declare const symbolKey: unique symbol;
510
+
511
+ type Example = {
512
+ // These index signatures will remain.
513
+ [x: string]: unknown;
514
+ [x: number]: unknown;
515
+ [x: symbol]: unknown;
516
+ [x: `head-${string}`]: string;
517
+ [x: `${string}-tail`]: string;
518
+ [x: `head-${string}-tail`]: string;
519
+ [x: `${bigint}`]: string;
520
+ [x: `embedded-${number}`]: string;
521
+
522
+ // These explicitly defined keys will be removed.
523
+ ['kebab-case-key']: string;
524
+ [symbolKey]: string;
525
+ foo: 'bar';
526
+ qux?: 'baz';
527
+ };
528
+
529
+ type ExampleIndexSignature = PickIndexSignature<Example>;
530
+ // {
531
+ // [x: string]: unknown;
532
+ // [x: number]: unknown;
533
+ // [x: symbol]: unknown;
534
+ // [x: `head-${string}`]: string;
535
+ // [x: `${string}-tail`]: string;
536
+ // [x: `head-${string}-tail`]: string;
537
+ // [x: `${bigint}`]: string;
538
+ // [x: `embedded-${number}`]: string;
539
+ // }
540
+ ```
541
+
542
+ @see OmitIndexSignature
543
+ @category Object
544
+ */
545
+ type PickIndexSignature<ObjectType> = {
546
+ [KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> ? KeyType : never]: ObjectType[KeyType];
547
+ };
548
+ // Merges two objects without worrying about index signatures.
549
+ type SimpleMerge<Destination, Source> = {
550
+ [Key in keyof Destination as Key extends keyof Source ? never : Key]: Destination[Key];
551
+ } & Source;
552
+ /**
553
+ Merge two types into a new type. Keys of the second type overrides keys of the first type.
554
+
555
+ @example
556
+ ```
557
+ import type {Merge} from 'type-fest';
558
+
559
+ interface Foo {
560
+ [x: string]: unknown;
561
+ [x: number]: unknown;
562
+ foo: string;
563
+ bar: symbol;
372
564
  }
373
565
 
374
- endIfEqual('abc', 'abc');
375
- //=> never
566
+ type Bar = {
567
+ [x: number]: number;
568
+ [x: symbol]: unknown;
569
+ bar: Date;
570
+ baz: boolean;
571
+ };
572
+
573
+ export type FooBar = Merge<Foo, Bar>;
574
+ // => {
575
+ // [x: string]: unknown;
576
+ // [x: number]: number;
577
+ // [x: symbol]: unknown;
578
+ // foo: string;
579
+ // bar: Date;
580
+ // baz: boolean;
581
+ // }
582
+ ```
376
583
 
377
- endIfEqual('abc', '123');
378
- //=> void
584
+ @category Object
585
+ */
586
+ type Merge<Destination, Source> = Simplify<SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>> & SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>>>;
587
+ /**
588
+ An if-else-like type that resolves depending on whether the given type is `any`.
589
+
590
+ @see {@link IsAny}
591
+
592
+ @example
593
+ ```
594
+ import type {IfAny} from 'type-fest';
595
+
596
+ type ShouldBeTrue = IfAny<any>;
597
+ //=> true
598
+
599
+ type ShouldBeBar = IfAny<'not any', 'foo', 'bar'>;
600
+ //=> 'bar'
379
601
  ```
380
602
 
381
603
  @category Type Guard
382
604
  @category Utilities
383
605
  */
384
- type IsNever<T> = [
385
- T
386
- ] extends [
387
- never
388
- ] ? true : false;
606
+ type IfAny<T, TypeIfAny = true, TypeIfNotAny = false> = (IsAny<T> extends true ? TypeIfAny : TypeIfNotAny);
389
607
  /**
390
608
  Works similar to the built-in `Pick` utility type, except for the following differences:
391
609
  - Distributes over union types and allows picking keys from any member of the union type.
@@ -427,6 +645,160 @@ type HomomorphicPick<T, Keys extends KeysOfUnion<T>> = {
427
645
  [P in keyof T as Extract<P, Keys>]: T[P];
428
646
  };
429
647
  /**
648
+ Merges user specified options with default options.
649
+
650
+ @example
651
+ ```
652
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
653
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
654
+ type SpecifiedOptions = {leavesOnly: true};
655
+
656
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
657
+ //=> {maxRecursionDepth: 10; leavesOnly: true}
658
+ ```
659
+
660
+ @example
661
+ ```
662
+ // Complains if default values are not provided for optional options
663
+
664
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
665
+ type DefaultPathsOptions = {maxRecursionDepth: 10};
666
+ type SpecifiedOptions = {};
667
+
668
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
669
+ // ~~~~~~~~~~~~~~~~~~~
670
+ // Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'.
671
+ ```
672
+
673
+ @example
674
+ ```
675
+ // Complains if an option's default type does not conform to the expected type
676
+
677
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
678
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'};
679
+ type SpecifiedOptions = {};
680
+
681
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
682
+ // ~~~~~~~~~~~~~~~~~~~
683
+ // Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
684
+ ```
685
+
686
+ @example
687
+ ```
688
+ // Complains if an option's specified type does not conform to the expected type
689
+
690
+ type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
691
+ type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
692
+ type SpecifiedOptions = {leavesOnly: 'yes'};
693
+
694
+ type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
695
+ // ~~~~~~~~~~~~~~~~
696
+ // Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
697
+ ```
698
+ */
699
+ type ApplyDefaultOptions<Options extends object, Defaults extends Simplify<Omit<Required<Options>, RequiredKeysOf<Options>> & Partial<Record<RequiredKeysOf<Options>, never>>>, SpecifiedOptions extends Options> = IfAny<SpecifiedOptions, Defaults, IfNever<SpecifiedOptions, Defaults, Simplify<Merge<Defaults, {
700
+ [Key in keyof SpecifiedOptions as Key extends OptionalKeysOf<Options> ? Extract<SpecifiedOptions[Key], undefined> extends never ? Key : never : Key]: SpecifiedOptions[Key];
701
+ }> & Required<Options>> // `& Required<Options>` ensures that `ApplyDefaultOptions<SomeOption, ...>` is always assignable to `Required<SomeOption>`
702
+ >>;
703
+ /**
704
+ Filter out keys from an object.
705
+
706
+ Returns `never` if `Exclude` is strictly equal to `Key`.
707
+ Returns `never` if `Key` extends `Exclude`.
708
+ Returns `Key` otherwise.
709
+
710
+ @example
711
+ ```
712
+ type Filtered = Filter<'foo', 'foo'>;
713
+ //=> never
714
+ ```
715
+
716
+ @example
717
+ ```
718
+ type Filtered = Filter<'bar', string>;
719
+ //=> never
720
+ ```
721
+
722
+ @example
723
+ ```
724
+ type Filtered = Filter<'bar', 'foo'>;
725
+ //=> 'bar'
726
+ ```
727
+
728
+ @see {Except}
729
+ */
730
+ type Filter<KeyType, ExcludeType> = IsEqual<KeyType, ExcludeType> extends true ? never : (KeyType extends ExcludeType ? never : KeyType);
731
+ type ExceptOptions = {
732
+ /**
733
+ Disallow assigning non-specified properties.
734
+
735
+ Note that any omitted properties in the resulting type will be present in autocomplete as `undefined`.
736
+
737
+ @default false
738
+ */
739
+ requireExactProps?: boolean;
740
+ };
741
+ type DefaultExceptOptions = {
742
+ requireExactProps: false;
743
+ };
744
+ /**
745
+ Create a type from an object type without certain keys.
746
+
747
+ We recommend setting the `requireExactProps` option to `true`.
748
+
749
+ 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.
750
+
751
+ 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)).
752
+
753
+ @example
754
+ ```
755
+ import type {Except} from 'type-fest';
756
+
757
+ type Foo = {
758
+ a: number;
759
+ b: string;
760
+ };
761
+
762
+ type FooWithoutA = Except<Foo, 'a'>;
763
+ //=> {b: string}
764
+
765
+ const fooWithoutA: FooWithoutA = {a: 1, b: '2'};
766
+ //=> errors: 'a' does not exist in type '{ b: string; }'
767
+
768
+ type FooWithoutB = Except<Foo, 'b', {requireExactProps: true}>;
769
+ //=> {a: number} & Partial<Record<"b", never>>
770
+
771
+ const fooWithoutB: FooWithoutB = {a: 1, b: '2'};
772
+ //=> errors at 'b': Type 'string' is not assignable to type 'undefined'.
773
+
774
+ // The `Omit` utility type doesn't work when omitting specific keys from objects containing index signatures.
775
+
776
+ // Consider the following example:
777
+
778
+ type UserData = {
779
+ [metadata: string]: string;
780
+ email: string;
781
+ name: string;
782
+ role: 'admin' | 'user';
783
+ };
784
+
785
+ // `Omit` clearly doesn't behave as expected in this case:
786
+ type PostPayload = Omit<UserData, 'email'>;
787
+ //=> type PostPayload = { [x: string]: string; [x: number]: string; }
788
+
789
+ // In situations like this, `Except` works better.
790
+ // It simply removes the `email` key while preserving all the other keys.
791
+ type PostPayload = Except<UserData, 'email'>;
792
+ //=> type PostPayload = { [x: string]: string; name: string; role: 'admin' | 'user'; }
793
+ ```
794
+
795
+ @category Object
796
+ */
797
+ type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {}> = _Except<ObjectType, KeysType, ApplyDefaultOptions<ExceptOptions, DefaultExceptOptions, Options>>;
798
+ type _Except<ObjectType, KeysType extends keyof ObjectType, Options extends Required<ExceptOptions>> = {
799
+ [KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
800
+ } & (Options["requireExactProps"] extends true ? Partial<Record<KeysType, never>> : {});
801
+ /**
430
802
  Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type.
431
803
 
432
804
  Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are optional.
@@ -1278,7 +1650,7 @@ type StorefrontQueryOptions = StorefrontCommonExtraParams & {
1278
1650
  cache?: CachingStrategy;
1279
1651
  };
1280
1652
  /**
1281
- * This function extends `createStorefrontClient` from [Hydrogen React](/docs/api/hydrogen-react/2025-10/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to Remix and Oxygen.
1653
+ * This function extends `createStorefrontClient` from [Hydrogen React](/docs/api/hydrogen-react/2026-01/utilities/createstorefrontclient). The additional arguments enable internationalization (i18n), caching, and other features particular to Remix and Oxygen.
1282
1654
  *
1283
1655
  * Learn more about [data fetching in Hydrogen](/docs/custom-storefronts/hydrogen/data-fetching/fetch-data).
1284
1656
  */
@@ -1304,13 +1676,13 @@ type StorefrontForDoc<TI18n extends I18nBase = I18nBase> = {
1304
1676
  CacheCustom?: typeof CacheCustom;
1305
1677
  /** Re-export of [`generateCacheControlHeader`](/docs/api/hydrogen/utilities/generatecachecontrolheader). */
1306
1678
  generateCacheControlHeader?: typeof generateCacheControlHeader;
1307
- /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2025-10/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details. */
1679
+ /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. See [`getPublicTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2026-01/utilities/createstorefrontclient#:~:text=%27graphql%27.-,getPublicTokenHeaders,-(props%3F%3A) for more details. */
1308
1680
  getPublicTokenHeaders?: ReturnType<typeof createStorefrontClient$1>['getPublicTokenHeaders'];
1309
- /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2025-10/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.*/
1681
+ /** Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint for API calls made from a server. See [`getPrivateTokenHeaders` in Hydrogen React](/docs/api/hydrogen-react/2026-01/utilities/createstorefrontclient#:~:text=storefrontApiVersion-,getPrivateTokenHeaders,-(props%3F%3A) for more details.*/
1310
1682
  getPrivateTokenHeaders?: ReturnType<typeof createStorefrontClient$1>['getPrivateTokenHeaders'];
1311
- /** Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/2025-10/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details. */
1683
+ /** Creates the fully-qualified URL to your myshopify.com domain. See [`getShopifyDomain` in Hydrogen React](/docs/api/hydrogen-react/2026-01/utilities/createstorefrontclient#:~:text=StorefrontClientReturn-,getShopifyDomain,-(props%3F%3A) for more details. */
1312
1684
  getShopifyDomain?: ReturnType<typeof createStorefrontClient$1>['getShopifyDomain'];
1313
- /** Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/2025-10/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.*/
1685
+ /** Creates the fully-qualified URL to your store's GraphQL endpoint. See [`getStorefrontApiUrl` in Hydrogen React](/docs/api/hydrogen-react/2026-01/utilities/createstorefrontclient#:~:text=storeDomain-,getStorefrontApiUrl,-(props%3F%3A) for more details.*/
1314
1686
  getApiUrl?: ReturnType<typeof createStorefrontClient$1>['getStorefrontApiUrl'];
1315
1687
  /** The `i18n` object passed in from the `createStorefrontClient` argument. */
1316
1688
  i18n?: TI18n;
@@ -2439,9 +2811,9 @@ type VariantOptionValue = {
2439
2811
  type VariantSelectorProps = {
2440
2812
  /** The product handle for all of the variants */
2441
2813
  handle: string;
2442
- /** Product options from the [Storefront API](/docs/api/storefront/2025-10/objects/ProductOption). Make sure both `name` and `values` are a part of your query. */
2814
+ /** Product options from the [Storefront API](/docs/api/storefront/2026-01/objects/ProductOption). Make sure both `name` and `values` are a part of your query. */
2443
2815
  options: Array<PartialProductOption> | undefined;
2444
- /** Product variants from the [Storefront API](/docs/api/storefront/2025-10/objects/ProductVariant). You only need to pass this prop if you want to show product availability. If a product option combination is not found within `variants`, it is assumed to be available. Make sure to include `availableForSale` and `selectedOptions.name` and `selectedOptions.value`. */
2816
+ /** Product variants from the [Storefront API](/docs/api/storefront/2026-01/objects/ProductVariant). You only need to pass this prop if you want to show product availability. If a product option combination is not found within `variants`, it is assumed to be available. Make sure to include `availableForSale` and `selectedOptions.name` and `selectedOptions.value`. */
2445
2817
  variants?: PartialDeep<ProductVariantConnection> | Array<PartialDeep<ProductVariant>>;
2446
2818
  /** By default all products are under /products. Use this prop to provide a custom path. */
2447
2819
  productPath?: string;