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