I wish that TS had better type narrowing for the JS standard library, though there's a lot of constraints and design limitations that make it impractical. I ran into a similar issue with the some() method on Array not narrowing types a while back [1]; that issue links to the same sort of issue with filter(), as well as issues where the TS team has discussed what they can and can't do in control flow analysis.
type UserId = `user_${string}`;
type GroupId = `group_${string}`;
const addUserId = (id: UserId) => {
// do something
}
const processId = (id: string) => {
if (id.startsWith('user_') {
// type error here:
addUserId(id);
} else if (otherCondition)
// do other things
}
}
Instead you define a function:
const isUserId = (some: string): some is UserId => some.startsWith('user_');
Now you can use it as follows:
const processId = (id: string) => {
if (isUserId(id)) {
// no more error:
addUserId(id);
} else if (otherCondition)
// do other things
}
}