core icon indicating copy to clipboard operation
core copied to clipboard

defineComponent generic type error

Open mengxiong10 opened this issue 3 years ago • 4 comments

Version

3.2.21

Reproduction link

github.com

Steps to reproduce

The type of the parameter props of the setup function and the generic type of DefineComponent<Props> should not be the same.

// overload 1: direct setup function
// (uses user defined props interface)
export function defineComponent<Props, RawBindings = object>(
  setup: (
    props: Readonly<Props>,
    ctx: SetupContext
  ) => RawBindings | RenderFunction
): DefineComponent<Props, RawBindings>

What is expected?

interface TestProps {
  name: string;
  age?: number;
}

export const Test = defineComponent<TestProps>(function Test(props) {
  return () => {
    return <div>{props.name}</div>;
  };
});
<Test />

The volar should prompt whether the prop name is required.

What is actually happening?

The volar don't prompt.


Would it be better?

type NonUndefinedable<T> = T extends undefined ? never : T;

export type DefinePropsToOptions<T> = {
  [K in keyof T]-?: Record<string, never> extends Pick<T, K>
    ? { type: PropType<NonUndefinedable<T[K]>> }
    : { type: PropType<T[K]>; required: true };
};

export function defineComponent<Props, RawBindings = object>(
  setup: (
    props: Readonly<Props>,
    ctx: SetupContext
  ) => RawBindings | RenderFunction
): DefineComponent<DefinePropsToOptions<Props>, RawBindings>


mengxiong10 avatar Nov 05 '21 08:11 mengxiong10

Declare a component like this, props are props that default to the browser’s native tags. Props cannot get name and age...😟 It seems to be inconsistent with the expected behavior, maybe I misunderstood it?

lzm0x219 avatar Nov 07 '21 16:11 lzm0x219

Declare a component like this, props are props that default to the browser’s native tags. Props cannot get name and age...😟 It seems to be inconsistent with the expected behavior, maybe I misunderstood it?

I think you should define props.

interface TestProps {
  name: string;
  age?: number;
}

export const Test = defineComponent<TestProps>(function Test(props) {
  return () => {
    return <div>{props.name}</div>;
  };
});

Test.props = ['name', 'age']

mengxiong10 avatar Nov 08 '21 01:11 mengxiong10

Declare a component like this, props are props that default to the browser’s native tags. Props cannot get name and age...😟 It seems to be inconsistent with the expected behavior, maybe I misunderstood it?

I think you should define props.

interface TestProps {
  name: string;
  age?: number;
}

export const Test = defineComponent<TestProps>(function Test(props) {
  return () => {
    return <div>{props.name}</div>;
  };
});

Test.props = ['name', 'age']

get!

lzm0x219 avatar Nov 08 '21 02:11 lzm0x219

像这样声明一个组件,props 是默认为浏览器原生标签的 props。道具无法获取名称和年龄...😟这似乎与预期的行为不一致,也许我误解了?

我认为你应该定义道具。

interface TestProps {
  name: string;
  age?: number;
}

export const Test = defineComponent<TestProps>(function Test(props) {
  return () => {
    return <div>{props.name}</div>;
  };
});

Test.props = ['name', 'age']

But,why? we should have a better way or api

yinxulai avatar Oct 10 '22 13:10 yinxulai

像这样声明一个组件,props 是默认为浏览器原生标签的 props。道具无法获取名称和年龄...😟这似乎与预期的行为不一致,也许我误解了?

我认为你应该定义道具。

interface TestProps {
  name: string;
  age?: number;
}

export const Test = defineComponent<TestProps>(function Test(props) {
  return () => {
    return <div>{props.name}</div>;
  };
});

Test.props = ['name', 'age']

But,why? we should have a better way or api

因为TS是不参与运行时的。在运行时会丢失所有类型的定义,就无法知道定义了哪些props。

@yinxulai

tansan-dev avatar Mar 02 '23 06:03 tansan-dev