given the following if statement:
interface MyData {
prop1?: number,
prop2?: number,
}
const x: MyData = {
prop1: 1,
prop2: 2,
}
function fun(a: number, b: number) {
console.log(a, b);
}
if (x.prop1 && x.prop2) {
fun(x.prop1, x.prop2);
}
the compiler is able to infer that inside the if body, x.prop1 is defined and x.prop2 is defined.
I want to give name to the condition by extracting it to a function.
function bothPropsDefined(prop1: number | undefined, prop2: number | undefined): boolean {
return !!prop1 && !!prop2;
}
if (bothPropsDefined(x.prop1, x.prop2)) {
fun(x.prop1, x.prop2);
}
but the compiler fails to conclude that in the if body, both props are defined.
// Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.(2345)
How can I give the compiler a hint that if bothPropsDefined
returns true, than prop1 and prop2 are defined?
I tried type guard:
function bothPropsDefinedGuard(prop1: number | undefined, prop2: number | undefined): prop1 is number {
return !!prop1 && !!prop2;
}
if (bothPropsDefinedGuard(x.prop1, x.prop2)) {
fun(x.prop1, x.prop2);
}
but I only managed to add guard to one property.
Update
for the question above, I managed to write:
function bothPropsDefinedGuard2(x: {prop1?: number, prop2?: number}): x is {prop1: number, prop2: number} {
return !!x.prop1 && !!x.prop2;
}
if (bothPropsDefinedGuard2(x) {
fun(x.prop1, x.prop2);
}
but my real case is a bit harder, as props come from multiple objects:
interface MyData1 {
prop1?: number,
}
interface MyData2 {
prop2?: number,
}
const x1: MyData1 = {
prop1: 1,
}
const x2: MyData2 = {
prop2: 2,
}
You are looking for custom type guards. Here is a solution:
const x: { prop1: number | undefined, prop2: number | undefined } = {
prop1: 1,
prop2: 2,
}
function fun(a: number, b: number) {
console.log(a, b);
}
// Custom type guard
function propDefined(prop: number | undefined): prop is number {
return typeof prop === 'number';
}
// Use
if (propDefined(x.prop1) && propDefined(x.prop2)) {
fun(x.prop1, x.prop2);
}
Note: You cannot have a type guard that changes the types for two arguments. A type guard can only narrow one argument eg prop is number
as shown.
My goal was to name the condition, so answer by @basarat is not ideal.
I ended up
This is not ideal as well, due to artificially added combined object, but lets me name the condition:
interface MyData1 {
prop1?: number,
}
interface MyData2 {
prop2?: number,
}
const x1: MyData1 = {
prop1: 1,
}
const x2: MyData2 = {
prop2: 2,
}
const xCombined: MyData = {
prop1: x1.prop1,
prop2: x2.prop2,
}
if (bothPropsDefinedGuard2(xCombined)) {
fun(xCombined.prop1, xCombined.prop2);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.