Reputation: 7360
interface A {
id?: string
}
interface B {
id: string
}
function test(a: A, b: A) {
if (!a.id && !b.id) { return }
let c: B = {
id: a.id || b.id
}
}
The error I get:
Types of property 'objectId' are incompatible. Type 'string | undefined' is not assignable to type 'string'. Type 'undefined' is not assignable to type 'string'.
How can I go around this? One between a.id
an b.id
is defined, so this shouldn't be a problem.
Of course disabling strickNullChecks
isn't an option.
tsc 2.4.2
Upvotes: 1
Views: 305
Reputation: 329953
As @daniel-klischies says, TypeScript's control-flow analysis is not up to the task and you need to help it. In this case, TypeScript is not trying to apply De Morgan's Laws to see that (!a.id && !b.id)
is the same as !(a.id || b.id)
. It would probably be possible to implement, but spending compiler time checking for this is probably not worth the added bit of control-flow completeness.
But since we know that those are identical, we can help TypeScript by using that identity:
function test(a: A, b: A) {
const id = a.id || b.id;
if (!id) return;
let c: B = { id: id };
}
This type checks as desired. Good luck!
Upvotes: 1
Reputation: 1135
Typescript cannot automatically deduce that at the line where you set your c
at least one id must be non-null. The reason for this is based on computability theory (i.e. it is just not possible to do this reliably and for all edge-cases).
So you will have to add a typecast manually:
let c: B = {
id: <string>(a.id || b.id)
}
Upvotes: 1