This is a byproduct of how typescript checks for excess properties. A little bit of background:
Type A is generally assignable from type B if type B has at least all the properties of type A. So for example, no error is expected when performing this assignment:
let someObject = { id: 3, name: 'Mike', lastName: 'Bob' }
let user: { id: number, name: string } = someObject // Ok since someobject has all the properties of user
let userWithPass : { id: number, name: string, pass: string } = someObject // Error since someobject does not have pass
The only time Typescript will complain about excess properties is when we try to directly assign an object literal to some object that has a known type:
// Error excess property lastName
let user: { id: number, name: string } = { id: 3, name: 'Mike', lastName: 'Bob' }
Now in your case, typescript will first infer the type of the result to map
to the type of the returned object literal, which is all valid, and then will check that this type is compatible with the IUser
array which it is, so no error since we never directly tried to assign the object literal to something of type IUser
.
We can ensure we get an error if we explicitly set the return type of the arrow function passed to map
const nextUsers: IUser[] = users.map((user: IUser) : IUser => ({
id: 3,
name: 'Mike',
ID: 152,
}));