svelte-carousel icon indicating copy to clipboard operation
svelte-carousel copied to clipboard

Could not find a declaration file for module 'svelte-carousel'

Open cloudlena opened this issue 2 years ago • 8 comments

I'm using the SvelteKit workaround:

<script lang="ts">
	let Carousel;
	onMount(async () => {
		const module = await import('svelte-carousel');
		Carousel = module.default;
	});
</script>

I'm also using TypeScript.

Here, I'm getting the following error:

Could not find a declaration file for module 'svelte-carousel'. '/home/lena/bespinian/bespinian.io-svelte/node_modules/svelte-carousel/src/main.js' implicitly has an 'any' type.
      Try `npm i --save-dev @types/svelte-carousel` if it exists or add a new declaration (.d.ts) file containing `declare module 'svelte-carousel';`

npm i --save-dev @types/svelte-carousel doesn't work because that package doesn't exist.

I'm not sure if the problem is related to the SvelteKit workaround or if this package is generally not typed (correctly) for TypeScript.

My current workaround for this issue is to add declare module 'svelte-carousel'; to src/app.d.ts. However, it feels like I shouldn't need to do that, if this package was typed correctly.

Furthermore, it would be very helpful to have typings for the Carousel class and its options. Currently, I'm just typing it as SvelteComponent explicitly.

cloudlena avatar Aug 22 '22 10:08 cloudlena

Hey! So this got me started and now I've built what I think is a correct representation of the types involved.


declare module 'svelte-carousel' {
	import { SvelteComponentTyped } from 'svelte';

	interface CarouselProps {
		arrows?: boolean = true; //Enables next/prev arrows
		infinite?: boolean = true; //Infinite looping
		initialPageIndex?: number = 0; //Page to start on
		duration?: number = 500; //Transition duration (ms)
		autoplay?: boolean = false; //Enables autoplay of pages
		autoplayDuration?: number = 3000; // Autoplay change interval (ms)
		autoplayDirection?: 'next' | 'prev' = 'next'; // Autoplay change direction (next or prev)
		pauseOnFocus?: boolean = false; //	Pauses on focus (for touchable devices - tap the carousel to toggle the autoplay, for non-touchable devices - hover over the carousel to pause the autoplay)
		autoplayProgressVisible?: boolean = false; //Shows autoplay duration progress indicator
		dots?: boolean = true; //	Current indicator dots
		timingFunction?: string = 'ease-in-out'; //CSS animation timing function
		swiping?: boolean = true; //	swiping
		particlesToShow?: number = 1; // Number elements to show
		particlesToScroll?: number = 1; //Number of elements to scroll
	}

	interface PageChangeEvent {
		detail: number;
	}

	interface CarouselEvents {
		pageChange: (event: PageChangeEvent) => void;
	}

	interface CarouselSlots {
		prev: string;
		next: string;
		dots: string;
		default: string;
	}

	export default class Carousel
		extends SvelteComponentTyped<CarouselProps, CarouselEvents, CarouselSlots> {
		goTo: (index: number, options?: { animated?: boolean }) => void;
		goToPrev: (options?: { animated?: boolean }) => void;
		goToNext: (options?: { animated?: boolean }) => void;
	}
}

Hope this helps someone or can get built in!

Cobular avatar Nov 23 '22 02:11 Cobular

Would be great to get types added to this package! Thank you for sharing the declaration, helped a lot! 👍

I noticed that the above declaration is missing a few things. It's possible to expose let:showNextPage on the component. I'm not sure how to correctly type that, but instead went with the bind:this={carousel} approach and carousel.goToNext to avoid it.

<!-- This shows typing errors as it's not declared in CarouselProps -->
<Carousel let:showPrevPage let:showNextPage>

ecker00 avatar Jan 17 '23 09:01 ecker00

Hi, you can write the CarouselSlots interface like this to type the slot props:

interface CarouselSlots {
  prev: string;
  next: string;
  dots: string;
  default: {
    showPrevPage: () => void;
    showNextPage: () => void;
    showPage: (index: number) => void;
    currentPageIndex: number;
    ...
  };
}

purindaisuki avatar Jan 31 '23 03:01 purindaisuki

I'm having a heck of a time with this.... where does the type declaration go??

JDL1995 avatar Feb 10 '23 20:02 JDL1995

I'm having a heck of a time with this.... where does the type declaration go??

I just put it into the src directory.

By the way it should be:

interface CarouselEvents {
  pageChange: PageChangeEvent;
}

Otherwise Typescript will complain when accessing event.detail

jokahr avatar Feb 21 '23 18:02 jokahr

Thanks! I've just had red squiggly lines for two weeks but since it works fine I don't complain XD

JDL1995 avatar Feb 22 '23 13:02 JDL1995

I have optimised the types a little. These also include the individual properties provided in each slot, as well as the default slot. Using CustomEvent for the pageChange event and promises for the returned functions for the reference variable.

Create this file under src/types/svelte-carousel.d.ts.

declare module "svelte-carousel" {
  import type { SvelteComponentTyped } from "svelte";

  interface CarouselProps {
    /**
     * Enables next/prev arrows
     */
    arrows?: boolean;
    /**
     * Infinite looping
     */
    infinite?: boolean;
    /**
     * Page to start on
     */
    initialPageIndex?: number;
    /**
     * Transition duration (ms)
     */
    duration?: number;
    /**
     * Enables autoplay of pages
     */
    autoplay?: boolean;
    /**
     *  Autoplay change interval (ms)
     */
    autoplayDuration?: number;
    /**
     *  Autoplay change direction (next or prev)
     */
    autoplayDirection?: "next" | "prev";
    /**
     * 	Pauses on focus (for touchable devices - tap the carousel to toggle the autoplay, for non-touchable devices - hover over the carousel to pause the autoplay)
     */
    pauseOnFocus?: boolean;
    /**
     * Shows autoplay duration progress indicator
     */
    autoplayProgressVisible?: boolean;
    /**
     * 	Current indicator dots
     */
    dots?: boolean;
    /**
     * CSS animation timing function
     */
    timingFunction?: string;
    /**
     * 	swiping
     */
    swiping?: boolean;
    /**
     *  Number elements to show
     */
    particlesToShow?: number;
    /**
     * Number of elements to scroll
     */
    particlesToScroll?: number;
  }

  interface CarouselEvents {
    pageChange: CustomEvent<number>;
  }

  interface CarouselSlots {
    prev: {
      showPrevPage: () => void;
    };
    next: {
      showNextPage: () => void;
    };
    dots: {
      showPage: (pageIndex: number) => void;
      currentPageIndex: number;
      pagesCount: number;
    };
    default: {
      showPrevPage: () => void;
      showNextPage: () => void;
      currentPageIndex: number;
      pagesCount: number;
      showPage: (pageIndex: number) => void;
      loaded: number[];
    };
  }

  export default class Carousel extends SvelteComponentTyped<
    CarouselProps,
    CarouselEvents,
    CarouselSlots
  > {
    goTo(pageIndex: number, options?: { animated?: boolean }): Promise<void>;
    goToPrev(options?: { animated?: boolean }): Promise<void>;
    goToNext(options?: { animated?: boolean }): Promise<void>;
  }
}

As for the Sveltekit support, I simply wrapped in browser as per the documentation

<script lang="ts">
	import Carousel from 'svelte-carousel';
	import { browser } from '$app/environment';
</script>

{#if browser}
	<Carousel>
		<div>yo 0</div>
		<div>yo 1</div>
		<div>yo 2</div>
		<div let:showPage let:pagesCount slot="dots">
			{#each Array(pagesCount) as _, pageIndex (pageIndex)}
				<button on:click={() => showPage(pageIndex)}>{pageIndex}</button>
			{/each}
		</div>
	</Carousel>
{/if}

imCorfitz avatar Mar 24 '23 17:03 imCorfitz

Anybody had any luck when trying to test files using jest that import Carousel? I receive the error

SyntaxError: Cannot use import statement outside a module

flagrare-espark avatar Oct 06 '23 04:10 flagrare-espark