Issue
With ...(isAdmin && isFirstLogin) && {role: Yup.string()} when isAdmin is false, then (isAdmin && isFirstLogin) evaluates to false. When this happens the rest of the boolean expression is ignored from the way javascript shortcuts out of evaluating the expression. It's at this point you are attempting to spread false into the schema but this fails since it isn't iterable.
Solution
You need to handle the "unhappy" false path by still providing a value that can be spread. Using a ternary allows you to test the isAdmin && isFirstLogin condition and return { role: Yup.string() } if true, and a spreadable empty object {} if false.
const isAdmin = true
let schema = {
fname: Yup.string().required('Required'),
lname: Yup.string().required('Required'),
...(isAdmin && isFirstLogin) ? { role: Yup.string() } : {},
};
const isFirstLogin = true;
const schema1 = {
fname: 'first',
lname: 'last',
...(true && isFirstLogin) ? { role: 'role' } : {},
};
const schema2 = {
fname: 'first',
lname: 'last',
...(false && isFirstLogin) ? { role: 'role' } : {},
};
const schema3 = {
fname: 'first',
lname: 'last',
...(true && false) ? { role: 'role' } : {},
};
console.log(schema1, schema2, schema3);
isFirstLogin, but being prefixed withisI would expect it to a boolean type.