Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions types/phoenix_live_view/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,33 @@ This package contains the type definitions for the [Phoenix LiveView](https://gi
npm install --save-dev @types/phoenix_live_view
```

## BREAKING CHANGE in 0.20.0
## BREAKING CHANGE in 0.20 and 1.0

The `ViewHook` interface has been modified to better reflect the type expected by developers writing their own hooks. It used to correspond to the type of the hook object as it is constructed by the Phoenix LiveView library internally, but it included properties which are not expected for developers to provide. This required casting or commenting to make the typescript compiler happy when declaring hooks.
To preserve the actual namespaces of the phoenix_live_view Javascript modules, we distinguish
three different exports:

The new `ViewHook` interface is now correct and only expects the hook functions that developers are expected to provide given the public API. But it still provides the previous interface as `ViewHookInternal` for those who need to use it.
* `ViewHookInterface` is the interface (contract) for a LiveView hook.
* `ViewHook` is the implemented class in the phoenix_live_view module that implements
`ViewHookInterface`
* `Hook` is the generic interface that uses intersection types to let developers
add additional functionality to an instance of a hook.

Besides, and it correctly assigns the `ViewHookInternal` type to `this` when writing a hook, so properties like `el`, `viewName`, and functions like `push_event` are all there. The `ViewHook` interface can also now be used as a generic for developers who want to assign their own functions and properties to the hook object.
The `Hook` interface only expects the hook functions that developers are expected to provide given the public API.

`Hook` correctly assigns the `ViewHookInterface` interface to `this` when writing a hook, so properties like `el` and functions like `push_event` are all there. The `Hook` interface can also now be used as a generic for developers who want to assign their own functions and properties to the hook object.

```typescript
const testHook: ViewHook = {
const testHook: Hook = {
mounted() {
const hook = this;
console.log("TestHook mounted", { element: this.el, viewName: this.viewName });
hook.pushEvent("hook-mounted", { name: "testHook" }, (reply, ref) => {
console.log("TestHook mounted", { element: this.el });
hook.pushEvent("hook-mounted", { name: "testHook" }, (reply: object, ref: number) => {
console.log(`Got hook-mounted reply ${JSON.stringify(reply)} ref ${ref}`);
});
},
};

const testHookWithExtendedPrototype: ViewHook<{ handleClick: (event: MouseEvent) => void }> = {
const testHookWithExtendedPrototype: Hook<{ handleClick: (event: MouseEvent) => void }> = {
mounted() {
this.handleClick = (event: MouseEvent) => {
console.log("click", event);
Expand All @@ -46,6 +53,5 @@ const MyHooks: HooksOptions = {
};

const liveSocket = new LiveSocket("/live", Socket, opts);

```

36 changes: 36 additions & 0 deletions types/phoenix_live_view/hooks.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import LiveSocket from "./live_socket";

export type OnReply = (reply: any, ref: number) => any;
export type CallbackRef = (customEvent: any, bypass: boolean) => string;

export interface ViewHookInterface {
el: HTMLElement;
liveSocket: LiveSocket;

mounted?: () => void;
updated?: () => void;
beforeUpdate?: () => void;
destroyed?: () => void;
reconnected?: () => void;
disconnected?: () => void;

js(): object;
pushEvent(event: string, payload: any, onReply?: OnReply): any;
pushEventTo(phxTarget: any, event: string, payload: object, onReply?: OnReply): any;
handleEvent(event: string, callback: any): CallbackRef;
removeHandleEvent(callbackRef: CallbackRef): void;
upload(name: any, files: any): any;
uploadTo(phxTarget: any, name: any, files: any): any;
}

export interface Hook<T extends object = {}> {
mounted?: (this: T & ViewHookInterface) => void;
beforeUpdate?: (this: T & ViewHookInterface) => void;
updated?: (this: T & ViewHookInterface) => void;
beforeDestroy?: (this: T & ViewHookInterface) => void;
destroyed?: (this: T & ViewHookInterface) => void;
disconnected?: (this: T & ViewHookInterface) => void;
reconnected?: (this: T & ViewHookInterface) => void;
}

export type HooksOptions = Record<string, Hook<any>>;
Loading
Loading