Godofbrowser/vuejs-dialog

[contribution] Typescript definition

darrensapalo opened this issue · 13 comments

Below is some unpolished work for the typescript definition of this library.

I am not sure how to contribute to the typescript @types npm registry, or how to write it specifically for publishing. Currently, the following code works for my use:

filename: vue-file-import.d.ts

Last updated: September 24, 2020

import Vue from "vue";

declare module "*.vue" {
	import Vue from "vue";
	export default Vue;
}

declare module 'vue/types/vue' {
	// Global properties can be declared
	// on the `VueConstructor` interface

	import VuejsDialog from 'vuejs-dialog';

	interface DialogOptions {
		html?: boolean,
		loader?: boolean,
		reverse?: boolean,
		okText?: string,
		cancelText?: string,
		animation?: ('zoom'|'bounce'|'fade'),
		type?: ('basic'|'soft'|'hard'),
		verification?: string,
		verificationHelp?: string,
		clicksCount?: number,
		backdropClose?: true,
		customClass?: string
	}

         interface DialogResult {
		close?: ()=>void,
		loading?: ()=>void,
		node?: DOMElement,
		data?: any
	}

	interface Vue {
		$dialog: {
			alert(message: string, options?: DialogOptions): DialogResult
			confirm(message: string, options?: DialogOptions): DialogResult
		},

	}
}

Dumping a set of resources here for providing typescript definitions:

https://www.detroitlabs.com/blog/2018/02/28/adding-custom-type-definitions-to-a-third-party-library/

Thank you @darrensapalo. I will look at this soon. Really appreciate the time and effort.

Thank you for your work. 🙂

It has been about a year since last update, has this been fixed yet? I can use it in my app by doing (this as any).$dialog.confirm('My message') but its a terrible way of doing things.
It there any reason why typescript is not supported?
edit: added tag : @Godofbrowser

An updated version, including Nuxt types:

filename: vuejs-dialog.d.ts:

declare module 'vuejs-dialog' {
  import { PluginFunction } from 'vue'

  export const install: PluginFunction<Record<string, unknown>>

  interface DialogOptions {
    html?: boolean
    loader?: boolean
    reverse?: boolean
    okText?: string
    cancelText?: string
    animation?: 'zoom' | 'bounce' | 'fade'
    type?: 'basic' | 'soft' | 'hard'
    verification?: string
    verificationHelp?: string
    clicksCount?: number
    backdropClose?: true
    customClass?: string
  }

  interface DialogResult {
    close?: () => void
    loading?: () => void
    node?: Element
    data?: unknown
  }

  module 'vue/types/vue' {
    interface Vue {
      $dialog: {
        alert(message: string, options?: DialogOptions): DialogResult 
        confirm(message: string, options?: DialogOptions): DialogResult 
      }
    }
  }

  module '@nuxt/types' {
    interface NuxtAppOptions {
      $dialog: {
        alert(message: string, options?: DialogOptions):DialogResult 
        confirm(message: string, options?: DialogOptions): DialogResult 
      }
    }
  }

  module 'vuex/types/index' {
    interface Store<S> {
      $dialog: {
        alert(message: string, options?: DialogOptions): DialogResult 
        confirm(message: string, options?: DialogOptions): DialogResult 
      }
    }
  }
}

If you havent yet; create a vue-shim.d.ts as well:

declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

Im not sure if Promise<Record<string, unknown>> is the best return type here? Let me know if not and i'll update the post.

--

Edit: Replaced Promise<Record<string, unknown>> with DialogResult

this.$dialog
.confirm("Are you sure you want to delete the item?", {
loader: true
})
.then(d => {
// do some delete action
d.close();
});

this gives me an error:

This expression is not callable.
Type '{}' has no call signatures.

111 | d.close();

I have added your vuejs-dialog.d.ts from above to the project, btw.

@ghard1961 Double check whether the complaint of your ts compiler is:

  1. Not being able to detect this.$dialog.confirm as a missing func definition, or
  2. The error is on your line 111, which is d.close(), not having call signatures.

If it is the latter, then the type definitions provided for this.$dialog.confirm() method works as expected. It is your function call of d.close() that is erroneous. From your error message, it appears to be that d is interpreted as an any or type, which prevents the typescript compiler from figuring out what functions are available for that variable. If this is the case- there isn't any issues with the ts definitions suggested above.

Better for you to set up a reproducible error via stackblitz or jsfiddle so that someone can assist you specifically for the issue you are encountering.

Unfortunately, the images you attached on your mail application doesn't show properly on GitHub where I am reviewing your feedback, so I can't see the images you're sharing.

Could you resend that? Let's take a peek.

Im not sure if Promise<Record<string, unknown>> is the best return type here? Let me know if not and i'll update the post.

After corresponding with @ghard1961 briefly about his issue above, it appears that Promise<Record<string, unknown>> is not the appropriate return type there. His screenshot revealed to me that its an object that has close, loading, and data variables in it. Reading through the readme, the return type of the promise is a dialog result object which has the following property/functions:

// Whenever a user clicks on proceed,
// the promise returned by the dialog call will be
// resolved with a dialog object with the following shape:

{
    close: function | sometimes | A method that can be used to close the dialog if it's in a loading state
    loading: function | sometimes | A method that can be used to stop the dialog loader
    node: DOMElement | sometimes | A DOM element which the directive was bound to, when triggered via a directive
    data: any | always | Data sent with the positive action. Useful in prompts or custom components where you have multiple proceed buttons
}

So Instead of using Promise<Record<string, unknown>>, I think it would be appropriate to add a DialogResult interface on the vue.d.ts file, as defined by the specs in the readme:

    interface DialogResult {
		close?: ()=>void,
		loading?: ()=>void,
		node?: DOMElement,
		data?: any
	}

Please see first post for updated example.

This vuejs-dialog.d.ts works for me. Thanks for the help!

`declare module 'vuejs-dialog' {
import { PluginFunction } from 'vue'

export const install: PluginFunction<Record<string, unknown>>

interface DialogResult {
close?: ()=>void,
loading?: ()=>void,
node?: DOMElement,
data?: any
}

interface DialogOptions {
html?: boolean
loader?: boolean
reverse?: boolean
okText?: string
cancelText?: string
animation?: 'zoom' | 'bounce' | 'fade'
type?: 'basic' | 'soft' | 'hard'
verification?: string
verificationHelp?: string
clicksCount?: number
backdropClose?: true
customClass?: string
}

module 'vue/types/vue' {
interface Vue {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}

module '@nuxt/types' {
interface NuxtAppOptions {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}

module 'vuex/types/index' {
interface Store {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}
}
`

That did not get stored like i figured it would. Try again here:

declare module 'vuejs-dialog' {
import { PluginFunction } from 'vue'

export const install: PluginFunction<Record<string, unknown>>

interface DialogResult {
close?: ()=>void,
loading?: ()=>void,
node?: DOMElement,
data?: any
}

interface DialogOptions {
html?: boolean
loader?: boolean
reverse?: boolean
okText?: string
cancelText?: string
animation?: 'zoom' | 'bounce' | 'fade'
type?: 'basic' | 'soft' | 'hard'
verification?: string
verificationHelp?: string
clicksCount?: number
backdropClose?: true
customClass?: string
}

module 'vue/types/vue' {
interface Vue {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}

module '@nuxt/types' {
interface NuxtAppOptions {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}

module 'vuex/types/index' {
interface Store {
$dialog: {
alert(message: string, options?: DialogOptions): Promise
confirm(message: string, options?: DialogOptions): Promise
}
}
}
}