1

I'm wondering if there's a (working) way to extend an implicit argument's type without a new variable,

For example:

;[{ firstName: "John", lastName: "Smith" }]
.map( person => {
  const newPerson = person as typeof person & { name: string }
  newPerson.name = `${newPerson.firstName} ${newPerson.lastName}`
  return newPerson
}

Something like...

.map( (person: person & { name: string } ) => ...

Can I use a generic for this?

5
  • Seems to work for me. Just need to change person.name to newPerson.name ? Commented Jan 8, 2023 at 5:51
  • hi @Psidom thanks for the fix, I'll make that edit. Was wondering if you could redefine an argument's type without creating a new variable. Commented Jan 8, 2023 at 5:54
  • 2
    Why not just return { ...person, name: '${person.firstName} ${person.lastName}'} ? Commented Jan 8, 2023 at 5:55
  • That's a great workaround! Just wondering if I could redefine the function's signature if there was a way to do that, I'll edit again. Commented Jan 8, 2023 at 5:58
  • @Sean that's not a workaround, rather the optimal solution. Take a look at my answer for the details. Commented Jan 8, 2023 at 11:53

3 Answers 3

1

extend an implicit argument's type without a new variable

No, whether the type was inferred or explicit, TypeScript will consider any extra property as a potential typo.

"Workarounds" are indeed re-typing (type assertion) or making a new variable, which explicitly say to TypeScript that the extra members are intentional.


This may look like a hindrance for seasoned JavaScript developers, for whom freely adding new properties is a very common practice.

This is one of the few situations where TypeScript does force you to code things quite differently than in plain JS.

Here it is more like an annoyance than a critical limitation, as the workaround is quite simple (BTW, in JS you could have used forEach instead, since you "rework" items, whereas map already points semantically to the TS solution, as explained by GuerricP's answer).

You can see it as the price to pay for type explicitness.

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

1 Comment

I appreciate this answer because I couldn't figure out why the situation was bothering me, and you put it into words: TypeScript is forcing me to create an object when I normally wouldn't need to in JS. Although I could just cast the array literal, so like you said it's just a minor inconvenience stemming from TS inferring the type.
1

You can define a new Type which you can use later on .

type NewPerson = Person & {name: string}

And the best approach I feel would be to return the map with

const newPersons: NewPerson[] = persons.map(person => {
   const {firstName, lastName} = person;
   const newPerson = {...person, name: `${firstName} ${lastName}`};
   return newPerson;
})

The advantage here is that as you have defined the type if anything changes the typescript would through error for the array which was returned by using map.

Comments

1

What you need is not extending the function argument but use your own return value, which is precisely what Array.prototype.map is meant for. Thus, map is typed like this in TypeScript:

interface Array<T> {
  // ...
  map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
  // ...
}

And U can be inferred from the map callback parameter, so just use TypeScript's inference feature:

const mapped = [{ firstName: "John", lastName: "Smith" }]
  .map((person) => ({ ...person, name: `${person.firstName} ${person.lastName}` }));

type Mapped = typeof mapped; // type Mapped = { name: string; firstName: string; lastName: string; }[]

TypeScript playground

1 Comment

Thanks! I forgot about object spread to clone and add fields like that, I appreciate how it lets you 1-line the function like that.

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.