5

So I'm new to Typescript and VueJS and all of its new features.
Everything works as it is supposed to be but I cannot get rid of my typescript error and using v-model at the same time.
I'm working on a webview for a member to check and change its attributes. I get my members data from an API and store it in a PiniaStore. This means I have several InputFields requiring numbers and strings for a member. AFAIK v-model is the way to go for InputFields.

 Type 'string | number | null | undefined' is not assignable to type 'Nullable<string>'.
  Type 'number' is not assignable to type 'Nullable<string>'.

All the suggested solutions of stackoverflow questions to this error like this one or this one don't fit to my problem AFAIK. I found a bad workaround, which I don't like using a Change Event instead of v-model in my template block and having the same error in my script but ignore it via //@ts-ignore.

First, all I really ask for is how to comment out a typescript error in a VueJs template block, already asked here.
Second, how do I solve this problem without having a typescript error?

Looking at the piece of code below, I have this error at v-model and don't know how to fix it:

<script setup lang="ts">
import { useMembershipStore } from "@/stores/membership";

const membershipStore = useMembershipStore();
membershipStore.getMembership();
const { membership } = storeToRefs(membershipStore);

function save() {
  if (membership.value) {
    membershipStore.updateMembership(membership.value);
  }
}
</script>


<template>
  <div v-if="membership === null" class="loading">
    <h2>Loading</h2>
  </div>
  <div v-else class="members-table">
    <div v-for="(value, key) in Object.keys(membership)" >
      <br />
      <InputText type="text"
        v-model="membership[value as keyof typeof membership]"
      />
    </div>
    <Button @click="save()" />
  </div>
</template>

Here are my type definitions: membershipstore.ts

export type MembershipStoreState = {
  membership: Member | null;
};

types.ts

export interface Member {
  id?: number;
  user_id?: string;
  user_attr: string | null;
  create_attr?: string | null;
  admin_attr?: string | null;
}

I also figured out where the type Nullable<string> comes from. It is from PrimeVues type definition of its component InputText, which can be found here:

export interface InputTextProps extends InputHTMLAttributes {
    /**
     * Value of the component.
     */
    modelValue?: Nullable<string>;
}

Full code example can be found here
Full code example with bad workaround using a change event, here

4
  • erm, you don't need Object.keys in v-for, v-for="(value, key) in membership" should be better Commented Nov 18, 2022 at 15:36
  • True even though the code is shorter now v-model="membership[key]" the error still remains... Commented Nov 18, 2022 at 17:07
  • instead of commenting typescript error it is better to address it, could you show what is type definitions of membership. Looking from error type definition is suppose to be string or null but you are passing number to it? Commented Nov 28, 2022 at 14:59
  • @A.Z thanks for your suggestion! I updated it. Commented Nov 30, 2022 at 16:23

1 Answer 1

2

I suppose you are defining membership: Member|null to check for loader <div v-if="membership === null" class="loading">

You can try this instead

export type MembershipStoreState = {
  membership: Member;
};

In HTML

<template>
  <div v-if="Object.keys(membership).length === 0" class="loading">
    <h2>Loading</h2>
  </div>
  <div v-else class="members-table">
    <div v-for="(value, key) in membership" > // thanks to @Dimava's comment
      <br />
      <InputNumber v-if = "key === 'id' || key === 'user_id'"
        v-model="membership[key]"
      />
      <InputText type="text" v-else
        v-model="membership[key]"
      />
    </div>
    <Button @click="save()" />
  </div>
</template>

Object.keys(membership).length === 0 Will check if you have popullated any of the keys of your interface otherwise it will return true and your loading will be visible

Sign up to request clarification or add additional context in comments.

3 Comments

The error still remains at v-model. I implemented all of your suggestions here. I feel the problem still lies in the definition of InputText of PrimeVue only accepting strings and no numbers like an id...
I see you are disabling :disabled="key === 'id' || key === 'user_id' || key === 'create_attr' || key === 'admin_attr'" for numbers so what if you have a conditional v-if where you show InputText and InputNumber by checking key? Edited my answer
Thats the solution!! Typescript can tell the difference! Thanks a lot for helping me understanding typescript a little bit better!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.