composition-api の defineComponent のジェネリクス
Vue で props を指定するときって、
export default defineComponent({
props: {
strProps: {
type: String,
required: true,
},
arrProps: {
type: Array as PropType<string[]>,
required: false,
},
},
})
みたいに書くと思うんですけど、defineComponent のジェネリクスに props の型が書けるというのを最近知った。
defineComponentのジェネリクスとpropsの型定義って両方やったほうがいいのかな
— tagucch (@tagucch) October 15, 2021
defineComponent<{ hoge: string }>(
props: {
hoge: string,
required: true
}
)
みたいな
ちょっと型を見てみる
手元では@nuxtjs/composition-api
を使っているんだけど、追ってったらこいつは@vue/composition-api
の型を import して一部独自のものを足して使っている感じだった。defineComponent は何も足されてなかったので@vue/composition-api
のほうを見ていく。
declare function defineComponent<
RawBindings,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {}
>(
options: ComponentOptionsWithoutProps<unknown, RawBindings, D, C, M>
): VueProxy<unknown, RawBindings, D, C, M>
declare function defineComponent<
PropNames extends string,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {},
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
options: ComponentOptionsWithArrayProps<PropNames, RawBindings, D, C, M>
): VueProxy<
Readonly<
{
[key in PropNames]?: any
}
>,
RawBindings,
D,
C,
M
>
declare function defineComponent<
Props,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {},
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
options: HasDefined<Props> extends true
? ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M, Props>
: ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
): VueProxy<PropsOptions, RawBindings, D, C, M>
初見だとマジでなにもわからない。RawBindings
を grep してみたけど定義がこのファイルにはなかった。
Data, ComputedOptions, MethodOptions とあるのはたぶん Vue の data, computed, methods のことを書けるのだろう、雑に追ったがそんな感じだった。
今回は props の定義だけをジェネリクスで渡しているので 3 つあるうちの最下段にある型が使われているのだと思う、Props 以外はデフォルト型が設定されている。2 段目のPropNames
は string の拡張なので違いそう。
ジェネリクスで注入されたProps
は defineComponent の引数のoptions: HasDefined<Props>
で使われてる。
HasDefined は以下のような感じで、Conditional Types でわちゃわちゃと書かれてるが、結局 boolean の値が帰りそう。
declare type Equal<Left, Right> = (<U>() => U extends Left ? 1 : 0) extends <
U
>() => U extends Right ? 1 : 0
? true
: false
declare type HasDefined<T> = Equal<T, unknown> extends true ? false : true
結局呼び出し元も Conditional Types で型が分かれてて、
HasDefined<Props> extends true ? ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M, Props> : ComponentOptionsWithProps<PropsOptions, RawBindings, D, C, M>
違いはComponentOptionsWithProps
に Props を渡しているかいないかだけっぽい。つまり props の定義があれば渡すしなければ渡さないっていうだけのことっぽい。
declare type ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions,
RawBindings = Data,
D = Data,
C extends ComputedOptions = {},
M extends MethodOptions = {},
Props = ExtractPropTypes<PropsOptions>
> = ComponentOptionsBase<Props, D, C, M> & {
props?: PropsOptions
emits?: (EmitsOptions | string[]) & ThisType<void>
setup?: SetupFunction<Props, RawBindings>
} & ThisType<ComponentRenderProxy<Props, RawBindings, D, C, M>>
ここらへんから追ってないけど、たぶん Props の定義を渡せるようになっているということっぽい。
emits とか setup とかも渡せそう。
結論
あんま知られてないけど渡せそう。