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
Access Data in render #191
Comments
I'm not sure what you are asking. Could you provide a complete exampe of your code that seems to not work as expected? |
@LinusBorg my question is how to get data from setup setup: () => ({ state: 5 })
render() {
return this.data.state; // TypeError: Cannot destructure property 'state' of 'this.data' as it is undefined.
} or this.$data.state, but this is not reflected in the types. by old way i can: setup: () => ({ state: 5 })
render() {
return (this as any).state;
} but it was weird before whether it changed now? |
there's not import { createComponent, h } from '@vue/component-api'
export default createComponent({
setup: () => {
const state = 5
return () => h('div', this.state)
} again, a really complete example would make this easier for me. |
import { createComponent, h } from '@vue/component-api'
export default createComponent({
setup: () => {
return { state: 5 };
},
render() {
return h('div', this.state); // for ts this has no state
}
}); but if export function createComponent<
Props,
RawBindings = Data,
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
// prettier-ignore
options: (
// prefer the provided Props, otherwise infer it from PropsOptions
HasDefined<Props> extends true
? ComponentOptionsWithProps<PropsOptions, RawBindings, Props>
: ComponentOptionsWithProps<PropsOptions, RawBindings>) &
Partial<RawBindings> &
Omit<Vue2ComponentOptions<Vue>, keyof ComponentOptionsWithProps<never, never>>
): VueProxy<PropsOptions, RawBindings>; import { createComponent, h } from '@vue/component-api'
export default createComponent({
setup: () => {
return { state: 5 };
},
render() {
return h('div', this.state); // for ts this has state
}
}); |
or better we can type: export interface ComponentOptions<
V extends Vue,
Data=DefaultData<V>,
Methods=DefaultMethods<V>,
Computed=DefaultComputed,
PropsDef=PropsDefinition<DefaultProps>,
Props=DefaultProps> {
...
render?(this: Data & ComponentOptions<...>, createElement: CreateElement, hack: RenderContext<Props>): VNode;
...
} and pass |
Not sure if this is related, but it also doesn't recognize data from object API: App.vue// App.ts
import { VNode } from 'vue'
import { createComponent, ref } from '@vue/composition-api'
export default createComponent({
name: 'app',
setup () {
return {
foo: 'foo'
}
},
props: {
fizz: String
},
data: () => ({
bar: 'bar'
}),
computed: {
buzz (): string {
return 'buzz'
}
},
render (h): VNode {
return h('div', [this.bar, this.fizz, this.buzz, this.foo])
}
}) Error log
Tried on new project with babel, typescript, eslint |
Also it's not a problem with just <script lang="ts">
import { createComponent } from '@vue/composition-api'
export default createComponent({
setup: () => ({ foo: 'foo' }),
props: {
bar: String
},
computed: {
buzz (): string {
return this.foo + this.bar
}
}
})
</script>
|
According to many of the specs, the composition-api/test/ssr/serverPrefetch.spec.js Lines 113 to 119 in 7456343
However, as reported in this issue, TypeScript does not reflect this. return {
project,
loading
}
},
render (h, context) {
this.project // ERROR: property does not exist on type
|
@bbugh @jacekkarczmarczyk // ComponentOptions2.d.ts
// ComponentOptions2 is Vue2ComponentOptions in composition api
import {
Vue,
ComponentOptions,
CreateElement,
VNode
} from "vue";
import { PropsDefinition } from "vue/types/options";
declare global {
type DefaultData<V> = object | ((this: V) => object);
type DefaultProps = Record<string, any>;
type DefaultMethods<V> = { [key: string]: (this: V, ...args: any[]) => any };
type DefaultComputed = { [key: string]: any };
interface ComponentOptions2<
V extends Vue,
Data = DefaultData<V>,
Methods = DefaultMethods<V>,
Computed = DefaultComputed,
PropsDef = PropsDefinition<DefaultProps>,
Props = DefaultProps
> extends ComponentOptions<V, Data, Methods, Computed, PropsDef, Props> {
render?(
this: Computed & Methods & Data & Props & V,
createElement: CreateElement
): VNode;
}
} and // composition-api.d.tsimport "@vue/composition-api";
import Vue, { VNode, VueConstructor } from "vue";
import { UnwrapRef } from "@vue/composition-api/dist/reactivity";
import { SetupContext as _SetupContext } from "@vue/composition-api";
declare global {
type SlotsData = {
[key: string]: (...args: any[]) => VNode[];
};
interface SetupContext<TEvents, TSlots = SlotsData> extends _SetupContext {
emit<TEvent extends keyof TEvents>(
event: TEvent,
data: TEvents[TEvent]
): void;
readonly slots: SlotsData & TSlots;
}
}
declare module "@vue/composition-api" {
type Equal<Left, Right> = (<U>() => U extends Left ? 1 : 0) extends <
U
>() => U extends Right ? 1 : 0
? true
: false;
type HasDefined<T> = Equal<T, unknown> extends true ? false : true;
type Data = {
[key: string]: unknown;
};
type ComponentPropsOptions<P = Data> = {
[K in keyof P]: Prop<P[K], true | false> | null;
};
type Prop<T, Required extends boolean> =
| PropOptions<T, Required>
| PropType<T>;
interface PropOptions<T = any, Required extends boolean = false> {
type?: PropType<T> | null;
required?: Required;
default?: T | null | undefined | (() => T | null | undefined);
validator?(value: any): boolean;
}
type PropType<T> = PropConstructor<T> | PropConstructor<T>[];
type PropConstructor<T> =
| {
new (...args: any[]): T & object;
}
| {
(): T;
};
type RequiredKeys<T, MakeDefaultRequired> = {
[K in keyof T]: T[K] extends
| {
required: true;
}
| (MakeDefaultRequired extends true
? {
default: any;
}
: never)
? K
: never;
}[keyof T];
type OptionalKeys<T, MakeDefaultRequired> = Exclude<
keyof T,
RequiredKeys<T, MakeDefaultRequired>
>;
type InferPropType<T> = T extends null
? any
: T extends {
type: null;
}
? any
: T extends
| ObjectConstructor
| {
type: ObjectConstructor;
}
? {
[key: string]: any;
}
: T extends Prop<infer V, true | false>
? V
: T;
type ExtractPropTypes<O, MakeDefaultRequired extends boolean = true> = {
readonly [K in RequiredKeys<O, MakeDefaultRequired>]: InferPropType<O[K]>;
} &
{
readonly [K in OptionalKeys<O, MakeDefaultRequired>]?: InferPropType<
O[K]
>;
};
type ComponentPropsOptions<P = Data> = {
[K in keyof P]: Prop<P[K], true | false> | null;
};
type ComponentInstance = InstanceType<VueConstructor>;
type ComponentRenderProxy<P = {}, S = {}, PublicProps = P> = {
$data: S;
$props: PublicProps;
$attrs: Data;
$refs: Data;
$slots: Data;
$root: ComponentInstance | null;
$parent: ComponentInstance | null;
$emit: (event: string, ...args: unknown[]) => void;
} & P &
S;
type VueConstructorProxy<PropsOptions, RawBindings> = {
new (): ComponentRenderProxy<
ExtractPropTypes<PropsOptions>,
UnwrapRef<RawBindings>,
ExtractPropTypes<PropsOptions, false>
>;
};
type VueProxy<PropsOptions, RawBindings> = ComponentOptions2<
// !!!!!!!!!!!!!
Vue,
UnwrapRef<RawBindings>,
never,
never,
PropsOptions,
ExtractPropTypes<PropsOptions, false>
> &
VueConstructorProxy<PropsOptions, RawBindings>;
interface SetupContext {
readonly attrs: Record<string, string>;
readonly slots: {
[key: string]: (...args: any[]) => VNode[];
};
readonly parent: ComponentInstance | null;
readonly root: ComponentInstance;
readonly listeners: {
[key: string]: Function;
};
emit(event: string, ...args: any[]): void;
}
type SetupFunction<Props, RawBindings> = (
this: void,
props: Props,
ctx: SetupContext
) => RawBindings | (() => VNode | null);
interface ComponentOptionsWithProps<
PropsOptions = ComponentPropsOptions,
RawBindings = Data,
Props = ExtractPropTypes<PropsOptions>
> {
props?: PropsOptions;
setup?: SetupFunction<Props, RawBindings>;
}
interface ComponentOptionsWithoutProps<Props = never, RawBindings = Data> {
props?: undefined;
setup?: SetupFunction<Props, RawBindings>;
}
function createComponent<RawBindings>(
options: ComponentOptionsWithoutProps<never, RawBindings>
): VueProxy<never, RawBindings>;
function createComponent<
Props,
RawBindings,
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
options: (HasDefined<Props> extends true
? ComponentOptionsWithProps<PropsOptions, RawBindings, Props>
: ComponentOptionsWithProps<PropsOptions, RawBindings>) &
Omit<
ComponentOptions2<
Vue,
UnwrapRef<RawBindings>,
{},
{},
{},
HasDefined<Props> extends true
? Props
: ExtractPropTypes<PropsOptions>
>, // !!!!!!!!!!!!!
keyof ComponentOptionsWithProps<never, never>
>
): VueProxy<PropsOptions, RawBindings>;
} |
@NikitaIT is there something in that patch you could add as a PR to this repo? Sounds like you've got it figured out. |
@bbugh I could, but I don’t think it is worth doing.
|
It seems this issue also occur with Vue own properties such as In the following component: import { provide, InjectionKey, defineComponent } from '@vue/composition-api';
import { VNode, CreateElement } from 'vue/types/umd';
import useToggle from './useToggle';
export const ToggleSymbol: InjectionKey<object> = Symbol();
export default defineComponent({
name: 'CToggle',
setup() {
const toggle = useToggle();
provide(ToggleSymbol, toggle);
},
render(h: CreateElement): VNode {
return h('div', this.$slots.default);
},
}); TypeScript throws:
Note that the component works as expected, it's just TypeScript being sassy. |
Should be covered in #406 |
At the time this issue was created, changes were needed in the typing of vue itself due to problems with this in render in Vue2ComponentOptions. |
@antfu My package-lock.json |
composition-api/src/component/component.ts
Lines 79 to 91 in 1672b6e
This is needed to get the
return
fromsetup
torender
asthis.data // RawBindings
.If now there is a way to do it right, I would like to know it.
The text was updated successfully, but these errors were encountered: