Subscribe on changes!

Generate runtime type check definition with the generic parameter of `FunctionalComponent` like seen with `defineProps`

avatar
Apr 20th 2022

What problem does this feature solve?

Remove the need for manually declaring prop types and still ensure correct runtime behavior when writing Functional Components props and emit? definitions in TypeScript as seen with defineProps/defineEmits.

What does the proposed API look like?

Using the existing FunctionalComponent type generic argument as with defineProps to generate runtime type checks.

const myFC: FunctionalComponent<{text: string}> = (props) => (
  <h1>{props.text}</h1>
)

// generate this automatically like defineProps<{...}>()
myFC.props = {
  text: {
    type: String as PropType<string>,
    default: '',
  },
}

Repro: https://stackblitz.com/edit/vue-issue-repro-5766?file=src%2Fcomponents%2FMyComponent.vue

avatar
Apr 29th 2022

I have updated my issue/feature proposal for better clarity.

Is there anything else I can help you with, so that this issue can be triaged? 🙂

avatar
Apr 30th 2022

You can use runtime type check like this:

stackblitz Example

SFC Example

avatar
Apr 30th 2022

Thanks! This is also a good alternative. It would be nice, if the Vue compiler could do this automatically.

avatar
Dec 7th 2022

I began to use Functional Components and being able to specify props with TypeScript it feels like something normal but unfortunately, it's not possible.

I hope we can have better support for Functional Components in the future

avatar
Feb 23rd 2024

我也遇到同样的问题,我是这样解决的,断言类型的方式 I also encountered the same problem, and I solved it this way by asserting types

//声明VElForm部分 Declare the VElForm section
export declare type VElFormProps<FormData> = {
  form: FormData
}
function VElForm<T>(props: VElFormProps<T>) {
  return `${props.form}`
}

export default VElForm as unknown as GenericForm

//声明GenericForm部分 Declare the GenericForm section
declare type GenericForm = <FormData>(
  props: {
    form: FormData
  } & CommonType,
  ctx?: Ctx,
  expose?: (exposed: import('vue').ShallowUnwrapRef<{}>) => void,
  setup?: Promise<
    ReturnInstance<{
      form: FormData
    }>
  >
) => RenderNodeType & {
  __ctx?: ReturnInstance<{
    form: FormData
  }>
}
declare type RenderNodeType = import('vue').VNode<
  import('vue').RendererNode,
  import('vue').RendererElement,
  { [key: string]: any }
>
declare type CommonType = import('vue').VNodeProps &
  import('vue').AllowedComponentProps &
  import('vue').ComponentCustomProps

declare type Ctx<S = {}, E = any> = {
  attrs: any
  slots: S
  emit: E
}
declare interface ReturnInstance<T> extends Ctx {
  props: T & CommonType
  expose(exposed: import('vue').ShallowUnwrapRef<{}>): void
}