In the code snippets below, the second last line in getChildEmail show no error here as child.email is no longer string|undefined but string only because of narrowing.
However, type error is shown in last line of getChildEmail. This is unexpected as child's type should now satisfy the type of getEmail's argument.
type Parent = {
name: string;
email?: string;
child: {
name: string;
email?: string;
};
};
function getEmail({ name, email }: { name: string; email: string }) {
return email;
}
function getChildEmail({ name, email, child }: Parent) {
child.email.toLocaleLowerCase(); // error as expected, child.email is possibly undefined
child.email && child.email.toLowerCase(); // working as expected, child.email is a string because of narrowing
child.email && getEmail(child); // unexpected error as narrowing should make child satisfies the arguments of getEmail function
}
Why is it the case? What's the best practice to remove the last line type error?
You can also view it in the following typescript playground
CodePudding user response:
One option is to cast the type of child to the correct type with a type assertion
child.email && getEmail(child as Required<Parent['child']>);
Looks a bit cleaner if we define a Child type too
type Child = {
name: string;
email?: string;
}
type Parent = {
name: string;
email?: string;
child: Child;
};
function getEmail({ name, email }: { name: string; email: string }) {
return email;
}
function getChildEmail({ name, email, child }: Parent) {
child.email?.toLocaleLowerCase();
child.email && child.email.toLowerCase();
child.email && getEmail(child as Required<Child>);
}
CodePudding user response:
One way to solve this is by adding a type guard (more about type guards, see here). Try something like this:
function hasEmail(person: { name: string; email?: string }): person is {name: string; email: string} {
return person.email !== undefined;
}
And then check it in this way:
hasEmail(child) && getEmail(child);
See the entire fixed code here.
CodePudding user response:
type Parent = {
name: string;
email?: string;
child: {
name: string;
email?: string;
};
};
function getEmail({ name, email }: any ) {
return email;
}
function getChildEmail({ name, email, child }: Parent) {
child?.email?.toLocaleLowerCase();
child.email && child.email.toLowerCase();
child.email && getEmail(child);
}
check your return type in getEmail() function. I think, it causes an error. As I understood, you only want to return email property, not child object
