npm package: @nolikein/types-livewire3
Description: Typescript content for Laravel Livewire 3
Author: Côme Wasik
Latest version: 2.0.9

# TypeScript support for Livewire 3

Allows you to use the power of TypeScript with Livewire 3.

## Recommandation

For more confort of code, you can use the [typed-alpinejs](https://www.npmjs.com/package/@nolikein/typed-alpinejs) package that allow you to create your components with a more elegant syntax. It uses that package internally so you don't need to install both packages.

## Migration From 1.x to 2.x

Now all your "LivewireMethods" interfaces should be a `Record<string, (...args: any) => any>` instead of `Record<string, any>`.

This means your code pass from:

```ts
interface LivewireMethods {
    open: ({ state: boolean })
}
```

To:

```ts
interface LivewireMethods extends LivewireMethodsRecord {
    open: (state: boolean) => ({ state: boolean })
}

// OR

type LivewireMethods = {
    open: (state: boolean) => ({ state: boolean })
}
```

! Please take care about extending your `LivewireData` with `LivewireDataRecord`:
```ts
interface LivewireData extends LivewireDataRecord {
    open: boolean
}
// OR

type LivewireData = {
    open: boolean
}
```


In order to keep the type safety of your methods parameters and return types.

## Installation

    npm i -D @nolikein/types-livewire3

## Usage

### Declare Livewire and AlpineJs into your project

First you need to install the alpineJs TypeScript definition.

    npm i -D @types/alpinejs

Look where is stored your main ts file (your entrypoint) and create at the same place a `livewire.d.ts` file.
```ts
// Note: "@/your_livewire_path" is an alias to the "vendor/livewire/livewire/dist/livewire.esm.js" file
declare module '@/your_livewire_path' {
    export const Livewire: import('@nolikein/types-livewire3').Livewire.Livewire;
    export const Alpine: import('@types/alpinejs').Alpine
}
```

Now you are able to use Livewire and Alpine inside your project. Here is an example with an index.ts file
```ts
import { Livewire, Alpine } from '@/your_livewire_path';

Alpine.data('YourComponent', () => {});
Livewire.start();
```

### Create an Alpine component that use a $wire instance

#### Use my dedicated package
Why complicating things when i created the easiest way to do it ? Follow [that link](https://www.npmjs.com/package/@nolikein/typed-alpinejs#user-content-alpinejs-with-livewire-3), install the package then read the instructions.


#### The hard way to learn

Here we create a Dropdown component inside a Livewire component that have a "state" public bool property and an "open" public method that return the "state" property as a value.
```ts
import { AlpineWired } from "@nolikein/types-livewire3";

/**
 * Create the types/interfaces of your component.
 */
// Your AlpineJs component properties and methods
interface AlpineData {
    open: boolean
    toggle(): void
    callBackendToOpen(): void
}

// Your Livewire public properties
interface LivewireData {
    // The livewire component has an "state" property that is a boolean
    state: boolean
}

// Your Livewire public methods
interface LivewireMethods {
    // The livewire component has an "open" method that you can call then return a boolean
    open(state: boolean): ({ state: boolean })
}

/**
 * Create your component
 */
export default (
    // Component parameters...
) => ({
    // Component properties ...
    open: false,

    // Component methods ...
    toggle(): void {
        this.open = !this.open;
    },

    callBackendToOpen(): void {
        this.$wire.$call('open', true).then(data) => {
            console.log("The livewire component has updated its open property with the value " + data.state);
        });
    },
}) satisfies AlpineWired.AlpineComponent<AlpineData, LivewireData, LivewireMethods>;


```

### Create an AlpineJS only component

#### Use my dedicated package
Why complicating things when i created the easiest way to do it ? Follow [that link](https://www.npmjs.com/package/@nolikein/typed-alpinejs#user-content-alpinejs-component-only), install the package then read the instructions.


#### The hard way to learn

```ts
import { Alpine } from "@nolikein/types-livewire3";

/**
 * Create the type/interface of your component.
 */
// Type version
type Component = Alpine.AlpineComponent<{
    open: boolean
    toggle(): void
    // Here is a method that pass "this" as a parameter named "self"
    // It is rarely used. The only case i found is when you use the method as a callback
    // See the component code to know more about it
    displayOpenState(self: Alpine.AlpineComponentSelf<Component>): void
}>

/**
 * Create your component
 */
export default (
    // Component parameters...
) => ({
    // Component properties ...
    open: false,

    // Component methods ...
    toggle(): void {
        this.open = !this.open;
    },

    /**
     * The hook that is run when the component is created.
     * 
     * You don't need to include it inside your component interface
     * since it is a part of the Alpine.AlpineComponent interface.
     */
    init(): void {
        // You can execute a component method as a callback and use "this"
        // inside of it with that pattern
        setTimeout(
            () => this.displayOpenState(this),
            1000,
        );
    },
    // A method that use "this" but named as "self".
    displayOpenState(self: Alpine.AlpineComponentSelf<Component>): void {
        console.log("Here is your open state: " + self.open);
    },
}) satisfies Component;

```

## Contribute

Feel free to open issues or make pull requests on [Gitlab](https://gitlab.com/Come-Wasik/typescript-support-for-livewire-3).

## Licence

[MIT](./LICENCE)