From f40c5a86068f9d56ff3167de3b58ac6a18b103dd Mon Sep 17 00:00:00 2001 From: Damian Glowala Date: Thu, 26 Feb 2026 08:18:38 +0100 Subject: [PATCH 1/3] fix: infer configured providers and their modifiers in `useImage` --- src/runtime/image.ts | 10 +++++----- src/types/image.ts | 12 ++++++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/runtime/image.ts b/src/runtime/image.ts index 764d32268..fa84d9cd3 100644 --- a/src/runtime/image.ts +++ b/src/runtime/image.ts @@ -10,7 +10,7 @@ export function createImage(globalOptions: CreateImageOptions) { options: globalOptions, } - const getImage: $Img['getImage'] = (input: string, options = {}) => { + const getImage = (input: string, options: ImageOptions = {}): ResolvedImage => { const image = resolveImage(ctx, input, options) // Prerender static images @@ -25,12 +25,12 @@ export function createImage(globalOptions: CreateImageOptions) { for (const presetName in globalOptions.presets) { $img[presetName] = ((source, modifiers, options) => - $img(source, modifiers, { ...globalOptions.presets[presetName], ...options })) as $Img[string] + $img(source, modifiers, { ...globalOptions.presets[presetName], ...options } as ImageOptions)) as $Img[string] } $img.options = globalOptions $img.getImage = getImage - $img.getMeta = ((input: string, options?: ImageOptions) => getMeta(ctx, input, options)) as $Img['getMeta'] + $img.getMeta = ((input: string, options?: ImageOptions) => getMeta(ctx, input, options)) as $Img['getMeta'] $img.getSizes = ((input: string, options: ImageSizesOptions) => getSizes(ctx, input, options)) as $Img['getSizes'] ctx.$img = $img as $Img @@ -38,7 +38,7 @@ export function createImage(globalOptions: CreateImageOptions) { return $img } -async function getMeta(ctx: ImageCTX, input: string, options?: ImageOptions) { +async function getMeta(ctx: ImageCTX, input: string, options?: ImageOptions) { const image = resolveImage(ctx, input, { ...options }) if (typeof image.getMeta === 'function') { @@ -49,7 +49,7 @@ async function getMeta(ctx: ImageCTX, input: string, options?: ImageOptions) { } } -function resolveImage(ctx: ImageCTX, input: string, options: ImageOptions): ResolvedImage { +function resolveImage(ctx: ImageCTX, input: string, options: ImageOptions): ResolvedImage { if (input && typeof input !== 'string') { throw new TypeError(`input must be a string (received ${typeof input}: ${JSON.stringify(input)})`) } diff --git a/src/types/image.ts b/src/types/image.ts index ae0f06ffc..e7a03866f 100644 --- a/src/types/image.ts +++ b/src/types/image.ts @@ -84,11 +84,15 @@ export interface ImageSizes { } export interface Img { - (source: string, modifiers?: ImageOptions['modifiers'], options?: ImageOptions): ResolvedImage['url'] + ( + source: string, + modifiers?: ImageOptions['modifiers'], + options?: ImageOptions + ): ResolvedImage['url'] options: CreateImageOptions - getImage: (source: string, options?: ImageOptions) => ResolvedImage - getSizes: (source: string, options?: ImageOptions, sizes?: string[]) => ImageSizes - getMeta: (source: string, options?: ImageOptions) => Promise + getImage: (source: string, options?: ImageOptions) => ResolvedImage + getSizes: (source: string, options?: ImageOptions, sizes?: string[]) => ImageSizes + getMeta: (source: string, options?: ImageOptions) => Promise } export type $Img = Img & { From 80613db102a911f7426531b3fd00f7abf43eab47 Mon Sep 17 00:00:00 2001 From: Damian Glowala Date: Thu, 26 Feb 2026 08:58:55 +0100 Subject: [PATCH 2/3] align fn definition with types --- src/runtime/image.ts | 20 ++++++++++---------- src/types/image.ts | 16 +++++++--------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/runtime/image.ts b/src/runtime/image.ts index fa84d9cd3..fe72c6bbf 100644 --- a/src/runtime/image.ts +++ b/src/runtime/image.ts @@ -3,7 +3,7 @@ import { hasProtocol, parseURL, joinURL, withLeadingSlash } from 'ufo' import { imageMeta } from './utils/meta' import { checkDensities, parseDensities, parseSize, parseSizes } from './utils' import { prerenderStaticImages } from './utils/prerender' -import type { ImageOptions, ImageSizesOptions, CreateImageOptions, ResolvedImage, ImageCTX, $Img, ImageSizes, ImageSizesVariant, ConfiguredImageProviders } from '@nuxt/image' +import type { ImageOptions, CreateImageOptions, ResolvedImage, ImageCTX, $Img, ImageSizes, ImageSizesVariant, ConfiguredImageProviders } from '@nuxt/image' export function createImage(globalOptions: CreateImageOptions) { const ctx: ImageCTX = { @@ -31,7 +31,7 @@ export function createImage(globalOptions: CreateImageOptions) { $img.options = globalOptions $img.getImage = getImage $img.getMeta = ((input: string, options?: ImageOptions) => getMeta(ctx, input, options)) as $Img['getMeta'] - $img.getSizes = ((input: string, options: ImageSizesOptions) => getSizes(ctx, input, options)) as $Img['getSizes'] + $img.getSizes = ((input: string, options?: ImageOptions) => getSizes(ctx, input, options)) as $Img['getSizes'] ctx.$img = $img as $Img @@ -124,9 +124,9 @@ function getPreset(ctx: ImageCTX, name?: string): ImageOptions { return ctx.options.presets[name] } -function getSizes(ctx: ImageCTX, input: string, opts: ImageSizesOptions): ImageSizes { +function getSizes(ctx: ImageCTX, input: string, opts?: ImageOptions): ImageSizes { // Merge preset options so preset-provided sizes/densities are respected - const preset = getPreset(ctx, opts.preset) + const preset = getPreset(ctx, opts?.preset) const merged = defu(opts, preset) const width = parseSize(merged.modifiers?.width) @@ -160,7 +160,7 @@ function getSizes(ctx: ImageCTX, input: string, opts: ImageSizesOptions): ImageS for (const density of densities) { srcsetVariants.push({ width: variant._cWidth * density, - src: getVariantSrc(ctx, input, opts, variant, density), + src: getVariantSrc(ctx, input, variant, density, opts), }) } } @@ -179,14 +179,14 @@ function getSizes(ctx: ImageCTX, input: string, opts: ImageSizesOptions): ImageS variant = { size: '', screenMaxWidth: 0, - _cWidth: opts.modifiers?.width as number, - _cHeight: opts.modifiers?.height as number, + _cWidth: opts?.modifiers?.width as number, + _cHeight: opts?.modifiers?.height as number, } } srcsetVariants.push({ width: density, - src: getVariantSrc(ctx, input, opts, variant, density), + src: getVariantSrc(ctx, input, variant, density, opts), }) } } @@ -232,10 +232,10 @@ function getSizesVariant(key: string, size: string, height: number | undefined, } } -function getVariantSrc(ctx: ImageCTX, input: string, opts: ImageSizesOptions, variant: ImageSizesVariant, density: number) { +function getVariantSrc(ctx: ImageCTX, input: string, variant: ImageSizesVariant, density: number, opts?: ImageOptions) { return ctx.$img!(input, { - ...opts.modifiers, + ...opts?.modifiers, width: variant._cWidth ? variant._cWidth * density : undefined, height: variant._cHeight ? variant._cHeight * density : undefined, }, diff --git a/src/types/image.ts b/src/types/image.ts index e7a03866f..5d4b058d0 100644 --- a/src/types/image.ts +++ b/src/types/image.ts @@ -19,17 +19,15 @@ export interface ResolvedImageModifiers extends ImageModifiers { type DefaultProvider = ProviderDefaults extends Record<'provider', unknown> ? ProviderDefaults['provider'] : never -export interface ImageOptions { - provider?: Provider +type Sizes = Record | string + +export interface ImageOptions { + provider?: TProvider preset?: string densities?: string modifiers?: Partial> - & ('modifiers' extends keyof ConfiguredImageProviders[Provider] ? ConfiguredImageProviders[Provider]['modifiers'] : Record) - sizes?: string | Record -} - -export interface ImageSizesOptions extends ImageOptions { - sizes: Record | string + & ('modifiers' extends keyof ConfiguredImageProviders[TProvider] ? ConfiguredImageProviders[TProvider]['modifiers'] : Record) + sizes?: Sizes } export type ProviderGetImage> = (src: string, options: Omit & { modifiers: Partial } & T, ctx: ImageCTX) => ResolvedImage @@ -91,7 +89,7 @@ export interface Img { ): ResolvedImage['url'] options: CreateImageOptions getImage: (source: string, options?: ImageOptions) => ResolvedImage - getSizes: (source: string, options?: ImageOptions, sizes?: string[]) => ImageSizes + getSizes: (source: string, options?: ImageOptions) => ImageSizes getMeta: (source: string, options?: ImageOptions) => Promise } From 92cf5823844202714ae74639cb328e9c6717337a Mon Sep 17 00:00:00 2001 From: Damian Glowala Date: Thu, 26 Feb 2026 09:06:07 +0100 Subject: [PATCH 3/3] remove generics fallback --- src/types/image.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/types/image.ts b/src/types/image.ts index 5d4b058d0..4281eb505 100644 --- a/src/types/image.ts +++ b/src/types/image.ts @@ -82,15 +82,15 @@ export interface ImageSizes { } export interface Img { - ( + ( source: string, modifiers?: ImageOptions['modifiers'], options?: ImageOptions ): ResolvedImage['url'] options: CreateImageOptions - getImage: (source: string, options?: ImageOptions) => ResolvedImage - getSizes: (source: string, options?: ImageOptions) => ImageSizes - getMeta: (source: string, options?: ImageOptions) => Promise + getImage: (source: string, options?: ImageOptions) => ResolvedImage + getSizes: (source: string, options?: ImageOptions) => ImageSizes + getMeta: (source: string, options?: ImageOptions) => Promise } export type $Img = Img & {