Subscribe on changes!

[Bug] Can not get props from defineComponent function in tsx file

avatar
Dec 5th 2022

Vue version

3.2.45

Link to minimal reproduction

https://github.com/Lyon1994/vue-issues-project/tree/issues-001

Steps to reproduce

cd ${PROJECT_DIR}
pnpm i
pnpm dev

Open Browser, then you can find 'undefined' in web page

image

What is expected?

HelloWorld.tsx can get valid props from parent component.

Do not display 'undefined'

What is actually happening?

HelloWorld.tsx can not get valid props from parent component. It display 'undefined'

System Info

System:
    OS: Linux 5.15 Deepin 20.7.1 20.7.1
    CPU: (8) x64 Intel(R) Core(TM) i7-4720HQ CPU @ 2.60GHz
    Memory: 3.74 GB / 15.52 GB
    Container: Yes
    Shell: 5.0.3 - /bin/bash
  Binaries:
    Node: 16.17.0 - /usr/local/bin/node
    Yarn: 1.22.17 - ~/.local/bin/yarn
    npm: 8.13.2 - ~/.local/bin/npm

Any additional comments?

HelloWorld Component:

export interface HelloWorldProps {
  msg: string;
}

export default defineComponent<HelloWorldProps>((props) => {
  const msg = ref(props.msg);
  if (!props.msg) {
    console.error(
      `Can not get props from defineComponent function in tsx file: props.msg=${props.msg}`
    );
  }
  return () => (
    <div>
      <h1>
        HelloWorld.tsx get props.msg {" => "}
        <span style="color:red;">{props.msg ?? msg.value ?? "undefined"}</span>
      </h1>
    </div>
  );
});
avatar
Dec 5th 2022

Vue component props can't be defined with types alone, they need to be defined at runtime as well.(*)

const component = defineComponent<HelloWorldProps>((props) => {
  const msg = ref(props.msg);
  if (!props.msg) {
    console.error(
      `Can not get props from defineComponent function in tsx file: props.msg=${props.msg}`
    );
  }
  return () => (
    <div>
      <h1>
        HelloWorld.tsx get props.msg {" => "}
        <span style="color:red;">{props.msg ?? msg.value ?? "undefined"}</span>
      </h1>
    </div>
  );
});

component.props = ['msg']
export default component

The above is roughly equivalent to the following, though that will likely break on a type level since the generic argument is being inferred from the props option:

export default defineComponent<HelloWorldProps>(
  props: ['msg'],
  setup: (props) => {
  const msg = ref(props.msg);
  if (!props.msg) {
    console.error(
      `Can not get props from defineComponent function in tsx file: props.msg=${props.msg}`
    );
  }
  return () => (
    <div>
      <h1>
        HelloWorld.tsx get props.msg {" => "}
        <span style="color:red;">{props.msg ?? msg.value ?? "undefined"}</span>
      </h1>
    </div>
  );
}
);

...or use a real functional component.


(*) Notes:

  1. in <script setup>, you can define props with types, but the compiler converts those to runtime definitions.
  2. in functional components, you don't need props. but components wrapped in defineComponent are not functional components - even when you pass a function: that function would be used as setup() in a normal component generated by defineComponent.
avatar
May 15th 2023

FYI: I have made a small unplugin to make the code work. https://github.com/so1ve/unplugin-vue-tsx-auto-props