Problem overview
addContact receives a phone book phoneBook, an object from names to phone numbers (both strings), a name and a number. It adds the name with its number and returns the phone book, but only when the name is not in the phone book yet. A name that is already there keeps its old number. The order of the entries doesn't matter.
With {"Ana": "555-0142", "Ben": "555-0199"} and "Cara" with "555-0123", Cara is added. With "Ben" and "555-0100" nothing changes, and Ben keeps "555-0199". With an empty phone book, "Max" becomes the only contact.
Approach
Assigning to a key replaces any value that is already there. That is why the check must come first: if the key exists, skip the assignment. The check is name in phoneBook, and ! in front of the whole check turns it into "name is not a key yet".
Step by step
- Write the condition.
if (!(name in phoneBook)), with the parentheses around theincheck. Without them,!would apply tonamealone, and the condition would be wrong for every name. Close the brace right away. - Store the number. Inside the
if,phoneBook[name] = number. Assigning to a key that isn't there adds it with its value. - Return the phone book after the
if, so it runs in both cases.
The solution in TypeScript
class Solution {
addContact(phoneBook: { [key: string]: string }, name: string, number: string): { [key: string]: string } {
if (!(name in phoneBook)) {
phoneBook[name] = number;
}
return phoneBook;
}
}
The type { [key: string]: string } says "an object with any string keys and string values". Running the three examples prints:
{ Ana: '555-0142', Ben: '555-0199', Cara: '555-0123' }
{ Ana: '555-0142', Ben: '555-0199' }
{ Max: '555-0100' }
Why the check comes first
In an object, writing phoneBook[name] = number does two jobs: it adds the key when it is new, and it overwrites the value when it already exists. Both are the same line of code, so the function cannot tell them apart unless you ask first. That is the purpose of the if: it keeps the second job from happening. The first example takes the if branch because "Cara" is not a key, and the second skips it because "Ben" is.
Also note that the check looks only at the name. The two numbers in the second example, the old "555-0199" and the new "555-0100", are never compared with each other.
Edge cases and common mistakes
- Existing name. Ben keeps
"555-0199". Assigning without the check would give him"555-0100", and the printed book would show{ Ben: '555-0100' }for that entry. - Empty phone book.
"Max" in {}is false, so Max is added. - Shared numbers. Two names may have the same number. Only the name is checked, never the number.
- Missing parentheses.
!name in phoneBookis read as(!name) in phoneBook. A non-empty name is truthy, so!nameisfalse, and the condition asks whether the key"false"exists. It doesn't, so nothing is ever added: the call with"Cara"returns{ Ana: '555-0142' }for a book that held only Ana. The compiler reports a type error here, but the JavaScript still runs and misbehaves. - The parameter named
number. It is allowed as a parameter name. TypeScript's typenumberand a variable callednumberlive in different places, so there is no clash. - The function changes the book it receives. It returns that same object, not a copy.
