2

I'm learning about typescript, and I'm struggling with this code below.

      const profile = state.currentProfile;
      type literalProfile = keyof Partial<Omit<Profile, 'id'>>;

      const values: Record<literalProfile, string | undefined> = {
        name: '',
        avatar: '',
        title: '',
        subtitle: '',
      };

      Object.entries(data).forEach((entry) => {
        const key = entry[0] as literalProfile;
        const value = entry[1];
        if (value && profile[key] !== value) {
          values[key] = value;
        }
      });

      await this.$axios.patch(`/users/profiles/${profile.id}`, values);

The question is, Is there any way to initialize values as an empty object, like this?

const values: Record<literalProfile, string | undefined> = {};

Because if I do something like this typescript highlight me an error

Type '{}' is missing the following properties from type 'Record<"name" | "title" | "subtitle" | "avatar", string | undefined>': name, title, subtitle, avatar

If I try something like this

let values: Record<literalProfile, string | undefined>;

Then typescript says

Variable 'values' is used before being assigned.

In this line

await this.$axios.patch(`/users/profiles/${profile.id}`, values);

So I don't know how to fix that, any ideas?

2
  • 5
    An empty object is not a valid value of that type, as it lacks the required properties. Perhaps you want Partial<Record<literalProfile, string>>? Or a type assertion to temporarily lie to the compiler about the type of the object while you initialize it? Either way I would prefer to see a minimal reproducible example here suitable for dropping into a standalone IDE like The TypeScript Playground to demonstrate the issue for myself. A self-contained toy example without axios would be nice. Commented Oct 8, 2020 at 19:49
  • Playground Link Your solution with Partial works great, I don't know why I don't realized about this solution. Despite, I would like to know what solution is more common practice among typescript developers, your solution or @wex solution. Thanks anyway! Commented Oct 8, 2020 at 20:52

1 Answer 1

3

Currently, you're using Record<listeralProfile, string | undefined>.

Instead, you should use { [key in literalProfile]?: string }.

There's a subtle difference. Both support undefined as a value, but by using the optional field keyword ? you can omit those fields when initializing your object.

const values: { [key in literalProfile]?: string } = {};
Sign up to request clarification or add additional context in comments.

3 Comments

Your solution works as expected, but I would like to know where I can read about the difference of your solution and Partial solution as @jcalz mentioned. Thanks in advance.
Wrapping your object in Partial basically adds the optional keyword to each field. You can read more here: typescriptlang.org/docs/handbook/utility-types.html#partialtype
In your case, it actually shouldn't make a difference which you use since every field is possibly an undefined value anyway.

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.