Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for props extraction on .vue #94

Closed
pikax opened this issue Mar 13, 2021 · 7 comments
Closed

Support for props extraction on .vue #94

pikax opened this issue Mar 13, 2021 · 7 comments
Labels
design limitation next-version Planned to resolve in next version

Comments

@pikax
Copy link
Member

pikax commented Mar 13, 2021

When you want to infer props from a base component, volar currently can't infer the props types (vuedx currently works)

This code works in typescript

const TestBase = defineComponent({
  props: {
    show: Boolean,
    title: String,
  },
});

type TestBaseType = typeof TestBase extends DefineComponent<
  infer Props,
  any,
  any,
  any,
  any,
  any,
  any,
  any
>
  ? Props
  : {};

const Child = defineComponent({
  props: {
    // props contains the props options
    ...(TestBase.props as TestBaseType),

    extra: String,
  },
  setup(props) {
    let i: boolean = props.show; // boolean
  },
});

But as soon as you separate into SFC types, the type gets lost:

// test.vue
<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  props: {
    show: Boolean,
    title: String,
  },
});
</script>

// Child.vue
<script lang="ts">
import { defineComponent } from 'vue';
import TestBase from './test.vue'

type TestBaseType = typeof TestBase extends DefineComponent<
  infer Props,
  any,
  any,
  any,
  any,
  any,
  any,
  any
>
  ? Props
  : {};

export default defineComponent({
  props: {
    // props contains the props options
    ...(TestBase.props as TestBaseType),

    extra: String,
  },
  setup(props) {
    // does not work beacuse TestBaseType will be `{}`
    let i: boolean = props.show; // boolean
  },
});
</script>
@johnsoncodehk
Copy link
Member

johnsoncodehk commented Mar 13, 2021

This is the design limit for now, because TestBase types is:

DefineComponent<...> & {
  __VLS_raw: DefineComponent<...>, // raw type
  __VLS_options: ..., // for template components, props, emits services
  __VLS_slots: ..., // for slots services
}

So it can't infer extends as DefineComponent. A simple reproduce:

const a = defineComponent({
  props: {
    show: Boolean,
    title: String,
  },
});
type A = typeof a & { __VLS_foo: any }
// We want B is true, but it's false
type B = A extends DefineComponent<
  infer _,
  any,
  any,
  any,
  any,
  any,
  any,
  any
> ? true : false;

If you accept a hack way, you can use typeof TestBase['__VLS_raw'] for now.

@johnsoncodehk johnsoncodehk added the bug Something isn't working label Mar 13, 2021
@pikax
Copy link
Member Author

pikax commented Mar 13, 2021

Will use that for now, do you think if the typed slots are implemented + GlobalComponents, will you still have the need of having?

DefineComponent<...> & {
  __VLS_raw: DefineComponent<...>, // raw type
  __VLS_options: ..., // for template components, props, emits services
  __VLS_slots: ..., // for slots services
}

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Mar 13, 2021

@pikax Yes it will better, but still need to use this way to support vue 2 / class component.

I will find a way to handle this problem. (The most extreme case I can create double typescript language service instances, half for <script>, half for <template>. :P)

@johnsoncodehk johnsoncodehk added design limitation and removed bug Something isn't working labels Mar 14, 2021
@lanyizi
Copy link

lanyizi commented Apr 9, 2021

I'm not sure if this bug has already been fixed, but the following one seems to be working:

import { ComponentOptions } from 'vue'
import Sfc from 'Sfc.vue'

type ExtractProp<Type> = Type extends ComponentOptions<infer Props>
  ? Props
  : never
type SfcProps = ExtractProp<typeof Sfc>;

@johnsoncodehk
Copy link
Member

@lanyizi not yet, but this problem may only occur with extends DefineComponent.

@johnsoncodehk
Copy link
Member

Fixed in volar@0.26.0 and vue-tsc@0.2.1.

@franco-onevillas
Copy link

Hey there, is it possible nowadays to infer types from a .vue file? I'm stuck in this exact case. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design limitation next-version Planned to resolve in next version
Projects
None yet
Development

No branches or pull requests

4 participants