vadimkorr / svelte-carousel

The awesome carousel component for Svelte 3 :arrow_left: :art: :arrow_right:
https://vadimkorr.github.io/svelte-carousel
Apache License 2.0
289 stars 64 forks source link

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

Open cloudlena opened 2 years ago

cloudlena commented 2 years ago

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.

Cobular commented 1 year ago

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!

ecker00 commented 1 year ago

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>
purindaisuki commented 1 year ago

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;
    ...
  };
}
JDL1995 commented 1 year ago

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

jokahr commented 1 year ago

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

JDL1995 commented 1 year ago

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

imCorfitz commented 1 year ago

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}
flagrare-espark commented 1 year ago

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