JonasKruckenberg / imagetools

Load and transform images using a toolbox :toolbox: of custom import directives!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use with typescript?

zoeleu opened this issue · comments

commented

How do I use 'import' with typescript?

@matteoturini
just tried this one (might not be the best solution)

// @ts-ignore
import srcsetWebp from '../example.jpg?w=500;700;900;1200&webp&srcset'
commented

@matteoturini
just tried this one (might not be the best solution)

// @ts-ignore
import srcsetWebp from '../example.jpg?w=500;700;900;1200&webp&srcset'

No typing. This is not a fix. Maybe make a flag so that you have to do something like this:

import example from '../example.jpg'

Config:

images: {
  'example.jpg': 'w=500;700;900;1200&webp&srcset'
}

Mentioning @JonasKruckenberg

You can also create a file, eg. typings.d.ts in your project with:

declare module "*.jpg?w=500;700;900;1200&webp&srcset"

Not ideal if you have a lot of different formats, but...

Yeah, there are a lot of less than ideal solutions to this problem, not much we can do from our side. The real fix is to lobby the typescript guys to allow multiple * in module declarations or allow search params to occur in any order.
But until then, presets will ease this a bit.

commented

Yeah, there are a lot of less than ideal solutions to this problem, not much we can do from our side. The real fix is to lobby the typescript guys to allow multiple * in module declarations or allow search params to occur in any order. But until then, presets will ease this a bit.

Yes, TypeScript could do that. But until then, is it possible to make importing with the config as I mentioned before?

A config object like you proposed will not be implemented. It's actually the exact thing that motivated this project. It'd should be obvious from looking at your source code what transformations are applied to your image instead of it being a declared somewhere else and applied "magically".
However, using the updated defaultDirectives you can implement type-able presets:

imagetools({
   defaultDirectives: id => {
      if (id.searchParams.has('hero')) { // the `hero` directive was set on the image
         return new URLSearchParams('width=1200;900;800&avif&metadata')
      }
      return new URLSearchParams()
   }
})

You can then type the preset:

declare module '*.jpg?hero' {
   const image: Record<string, any>
   export default image
}

I'm sorry if this is disappointing to you, but exactly the feature you asked for was the annoyance I experienced with the webpack-responsive-loader (they seem to also support url directives now!) and will therefore not be part of this plugin. I know that this type issue is super annoying; everything is a tradeoff however, and I feel that manual typing is still the better DX than "magic image transformation"

However, using the updated defaultDirectives you can implement type-able presets:

This got released in vite-imagetools@4.0.0 and rollup-plugin-imagetools@3.0.0 respectively.
I feel like this provides enough workarounds for the use in typescript so I'll close this for now. Feel free to reopen if the situation changes!

commented

as another workaround, for anyone else finding this

rather than create a preset without values, i added

declare module "*&imagetools" {
  /**
   * actual types
   * - code https://github.com/JonasKruckenberg/imagetools/blob/main/packages/core/src/output-formats.ts
   * - docs https://github.com/JonasKruckenberg/imagetools/blob/main/docs/guide/getting-started.md#metadata
   */
  const out;
  export default out;
}

to my globals.d.ts (i'm using sveltekit), and then added &imagetools to the end of my imports, e.g.

import image from "$lib/assets/image.jpg?w=200;400&format=webp;png&meta&imagetools";

imagetools seems to happily ignore the extra query parameter.

this is a bit verbose, but i liked it better than not being able to specify values.

also, one could add specific typing this way, e.g. by

declare module "*&meta&imagetools" {
  ...
}
commented

thats an awesome and creative solution, thanks!

commented

With the plugin configured as follows, the imported image ending with ?gallery returns an array of two objects.

imagetools({
  defaultDirectives: (id) => {
    if (id.searchParams.has("gallery")) {
      return new URLSearchParams("w=300;600&format=webp&as=metadata");
    }
    return new URLSearchParams();
  },
}),
import sampleImage from "@/assets/images/sample_image.jpeg?gallery";
console.log(sampleImage);

Output
image

You then can define the type for the values of interest.

declare module "*?gallery" {
  const images: {
    width: string;
    src: string;
  }[];
  export default images;
}

Now, as you can see, you can access the low res image as sampleImage[0].src and high res with sampleImage[1].src

Imagetools can return:

  • A string
  • An array of strings
  • An object
  • An array of objects

I have updated my types like this to reflect that. You know best what type of import to use in your application:

interface OutputMetadata {
    src: string; // URL of the generated image
    width: number; // Width of the image
    height: number; // Height of the image
    format: string; // Format of the generated image

    // The following options are the same as sharps input options
    space: string; // Name of colour space interpretation
    channels: number; // Number of bands e.g. 3 for sRGB, 4 for CMYK
    density: number; //  Number of pixels per inch
    depth: string; // Name of pixel depth format
    hasAlpha: boolean; // presence of an alpha transparency channel
    hasProfile: boolean; // presence of an embedded ICC profile
    isProgressive: boolean; // indicating whether the image is interlaced using a progressive scan
}

declare module "*&as=metadata&imagetools-gallery" {
    const outputs: Array<OutputMetadata>;
    export default outputs;
}

declare module "*&as=metadata&imagetools" {
    const outputs: OutputMetadata;
    export default outputs;
}

declare module "*&imagetools-gallery" {
    const outputs: Array<string>;
    export default outputs;
}

declare module "*&imagetools" {
    const outputs: string;
    export default outputs;
}