Skip to content

Commit

Permalink
🤖 Merge PR DefinitelyTyped#71578 phoenix_live_view 1.0, metadata Live…
Browse files Browse the repository at this point in the history
…Socket option by @pzingg
  • Loading branch information
pzingg authored Jan 18, 2025
1 parent 42bb005 commit d52d9d9
Show file tree
Hide file tree
Showing 12 changed files with 832 additions and 457 deletions.
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

0 comments on commit d52d9d9

Please sign in to comment.