Skip to content

Commit

Permalink
fix(type): improve defineComponent type for option apis (#406)
Browse files Browse the repository at this point in the history
* fix(type): improve defineComponent type for option apis

* test: add dts tests for defineComponent
fix
  • Loading branch information
antfu committed Jun 24, 2020
1 parent 048b6d3 commit 1c64108
Show file tree
Hide file tree
Showing 9 changed files with 854 additions and 171 deletions.
1 change: 1 addition & 0 deletions src/component/common.ts
@@ -0,0 +1 @@
export type Data = { [key: string]: unknown }
161 changes: 0 additions & 161 deletions src/component/component.ts

This file was deleted.

100 changes: 100 additions & 0 deletions src/component/componentOptions.ts
@@ -0,0 +1,100 @@
import { Data } from './common'
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
import { VNode } from 'vue'
import { ComponentInstance, ComponentRenderProxy } from './componentProxy'

import { ComponentOptions as Vue2ComponentOptions } from 'vue'

export interface SetupContext {
readonly attrs: Record<string, string>
readonly slots: { [key: string]: (...args: any[]) => VNode[] }
readonly parent: ComponentInstance | null
readonly root: ComponentInstance
readonly listeners: { [key: string]: Function }

emit(event: string, ...args: any[]): void
}

export type ComputedGetter<T> = (ctx?: any) => T
export type ComputedSetter<T> = (v: T) => void

export interface WritableComputedOptions<T> {
get: ComputedGetter<T>
set: ComputedSetter<T>
}

export type ComputedOptions = Record<
string,
ComputedGetter<any> | WritableComputedOptions<any>
>

export interface MethodOptions {
[key: string]: Function
}

export type SetupFunction<Props, RawBindings> = (
this: void,
props: Props,
ctx: SetupContext
) => RawBindings | (() => VNode | null)

interface ComponentOptionsBase<
Props,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {}
>
extends Omit<
Vue2ComponentOptions<Vue, D, M, C, Props>,
'data' | 'computed' | 'method' | 'setup' | 'props'
> {
data?: (this: Props, vm: Props) => D
computed?: C
methods?: M
}

export type ExtractComputedReturns<T extends any> = {
[key in keyof T]: T[key] extends { get: (...args: any[]) => infer TReturn }
? TReturn
: T[key] extends (...args: any[]) => infer TReturn
? TReturn
: never
}

export type ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {},
Props = ExtractPropTypes<PropsOptions>
> = ComponentOptionsBase<Props, D, C, M> & {
props?: PropsOptions
setup?: SetupFunction<Props, RawBindings>
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>

export type ComponentOptionsWithArrayProps<
PropNames extends string = string,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {},
Props = Readonly<{ [key in PropNames]?: any }>
> = ComponentOptionsBase<Props, D, C, M> & {
props?: PropNames[]
setup?: SetupFunction<Props, RawBindings>
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>

export type ComponentOptionsWithoutProps<
Props = unknown,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {}
> = ComponentOptionsBase<Props, D, C, M> & {
props?: undefined
setup?: SetupFunction<Props, RawBindings>
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>

export type WithLegacyAPI<T, D, C, M, Props> = T &
Omit<Vue2ComponentOptions<Vue, D, M, C, Props>, keyof T>
2 changes: 1 addition & 1 deletion src/component/componentProps.ts
@@ -1,4 +1,4 @@
import { Data } from './component'
import { Data } from './common'

export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
Expand Down
69 changes: 69 additions & 0 deletions src/component/componentProxy.ts
@@ -0,0 +1,69 @@
import { ExtractPropTypes } from './componentProps'
import { UnwrapRef } from '..'
import { Data } from './common'

import Vue, {
VueConstructor,
ComponentOptions as Vue2ComponentOptions,
} from 'vue'
import {
ComputedOptions,
MethodOptions,
ExtractComputedReturns,
} from './componentOptions'

export type ComponentInstance = InstanceType<VueConstructor>

// public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option)
export type ComponentRenderProxy<
P = {}, // props type extracted from props option
B = {}, // raw bindings returned from setup()
D = {}, // return from data()
C extends ComputedOptions = {},
M extends MethodOptions = {},
PublicProps = P
> = {
$data: D
$props: Readonly<P & PublicProps>
$attrs: Data
$refs: Data
$slots: Data
$root: ComponentInstance | null
$parent: ComponentInstance | null
$emit: (event: string, ...args: unknown[]) => void
} & Readonly<P> &
UnwrapRef<B> &
D &
M &
ExtractComputedReturns<C> &
Vue

// for Vetur and TSX support
type VueConstructorProxy<PropsOptions, RawBindings> = VueConstructor & {
new (...args: any[]): ComponentRenderProxy<
ExtractPropTypes<PropsOptions>,
UnwrapRef<RawBindings>,
ExtractPropTypes<PropsOptions, false>
>
}

type DefaultData<V> = object | ((this: V) => object)
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any }
type DefaultComputed = { [key: string]: any }

export type VueProxy<
PropsOptions,
RawBindings,
Data = DefaultData<Vue>,
Computed = DefaultComputed,
Methods = DefaultMethods<Vue>
> = Vue2ComponentOptions<
Vue,
UnwrapRef<RawBindings> & Data,
Methods,
Computed,
PropsOptions,
ExtractPropTypes<PropsOptions, false>
> &
VueConstructorProxy<PropsOptions, RawBindings>

0 comments on commit 1c64108

Please sign in to comment.