mirror of https://github.com/vuejs/core.git
types(runtime-core): support plugin options type inference (#3969)
This commit is contained in:
parent
584eae60d1
commit
c513126c5d
|
|
@ -31,7 +31,13 @@ import { ObjectEmitsOptions } from './componentEmits'
|
|||
export interface App<HostElement = any> {
|
||||
version: string
|
||||
config: AppConfig
|
||||
use(plugin: Plugin, ...options: any[]): this
|
||||
|
||||
use<Options extends unknown[]>(
|
||||
plugin: Plugin<Options>,
|
||||
...options: Options
|
||||
): this
|
||||
use<Options>(plugin: Plugin<Options>, options: Options): this
|
||||
|
||||
mixin(mixin: ComponentOptions): this
|
||||
component(name: string): Component | undefined
|
||||
component(name: string, component: Component): this
|
||||
|
|
@ -140,12 +146,16 @@ export interface AppContext {
|
|||
filters?: Record<string, Function>
|
||||
}
|
||||
|
||||
type PluginInstallFunction = (app: App, ...options: any[]) => any
|
||||
type PluginInstallFunction<Options> = Options extends unknown[]
|
||||
? (app: App, ...options: Options) => any
|
||||
: (app: App, options: Options) => any
|
||||
|
||||
export type Plugin =
|
||||
| (PluginInstallFunction & { install?: PluginInstallFunction })
|
||||
export type Plugin<Options = any[]> =
|
||||
| (PluginInstallFunction<Options> & {
|
||||
install?: PluginInstallFunction<Options>
|
||||
})
|
||||
| {
|
||||
install: PluginInstallFunction
|
||||
install: PluginInstallFunction<Options>
|
||||
}
|
||||
|
||||
export function createAppContext(): AppContext {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
import { createApp, App, Plugin } from './index'
|
||||
|
||||
const app = createApp({})
|
||||
|
||||
// Plugin without types accept anything
|
||||
const PluginWithoutType: Plugin = {
|
||||
install(app: App) {}
|
||||
}
|
||||
|
||||
app.use(PluginWithoutType)
|
||||
app.use(PluginWithoutType, 2)
|
||||
app.use(PluginWithoutType, { anything: 'goes' }, true)
|
||||
|
||||
type PluginOptions = {
|
||||
option1?: string
|
||||
option2: number
|
||||
option3: boolean
|
||||
}
|
||||
|
||||
const PluginWithObjectOptions = {
|
||||
install(app: App, options: PluginOptions) {
|
||||
options.option1
|
||||
options.option2
|
||||
options.option3
|
||||
}
|
||||
}
|
||||
|
||||
for (const Plugin of [
|
||||
PluginWithObjectOptions,
|
||||
PluginWithObjectOptions.install
|
||||
]) {
|
||||
// @ts-expect-error: no params
|
||||
app.use(Plugin)
|
||||
|
||||
// @ts-expect-error option2 and option3 (required) missing
|
||||
app.use(Plugin, {})
|
||||
// @ts-expect-error type mismatch
|
||||
app.use(Plugin, undefined)
|
||||
// valid options
|
||||
app.use(Plugin, { option2: 1, option3: true })
|
||||
app.use(Plugin, { option1: 'foo', option2: 1, option3: true })
|
||||
}
|
||||
|
||||
const PluginNoOptions = {
|
||||
install(app: App) {}
|
||||
}
|
||||
|
||||
for (const Plugin of [PluginNoOptions, PluginNoOptions.install]) {
|
||||
// no args
|
||||
app.use(Plugin)
|
||||
// @ts-expect-error unexpected plugin option
|
||||
app.use(Plugin, {})
|
||||
// @ts-expect-error only no options is valid
|
||||
app.use(Plugin, undefined)
|
||||
}
|
||||
|
||||
const PluginMultipleArgs = {
|
||||
install: (app: App, a: string, b: number) => {}
|
||||
}
|
||||
|
||||
for (const Plugin of [PluginMultipleArgs, PluginMultipleArgs.install]) {
|
||||
// @ts-expect-error: 2 arguments expected
|
||||
app.use(Plugin, 'hey')
|
||||
app.use(Plugin, 'hey', 2)
|
||||
}
|
||||
|
||||
const PluginOptionalOptions = {
|
||||
install(
|
||||
app: App,
|
||||
options: PluginOptions = { option2: 2, option3: true, option1: 'foo' }
|
||||
) {
|
||||
options.option1
|
||||
options.option2
|
||||
options.option3
|
||||
}
|
||||
}
|
||||
|
||||
for (const Plugin of [PluginOptionalOptions, PluginOptionalOptions.install]) {
|
||||
// both version are valid
|
||||
app.use(Plugin)
|
||||
app.use(Plugin, undefined)
|
||||
|
||||
// @ts-expect-error option2 and option3 (required) missing
|
||||
app.use(Plugin, {})
|
||||
// valid options
|
||||
app.use(Plugin, { option2: 1, option3: true })
|
||||
app.use(Plugin, { option1: 'foo', option2: 1, option3: true })
|
||||
}
|
||||
|
||||
// still valid but it's better to use the regular function because this one can accept an optional param
|
||||
const PluginTyped: Plugin<PluginOptions> = (app, options) => {}
|
||||
|
||||
// @ts-expect-error: needs options
|
||||
app.use(PluginTyped)
|
||||
app.use(PluginTyped, { option2: 2, option3: true })
|
||||
Loading…
Reference in New Issue