Reputation: 478
i am trying to have union of possible objects and to transform one to another
but both typescript and flow fail to recognize that boolean is true or false and nothing else and it's ok to assign boolean to object onion where it needs ether true literal or false literal
type Aa = {
isFetching: false,
isFailed: false,
isFetched: false
}
type Bb = {
isFetching: true,
isFailed: false,
isFetched: false
}
type Cc = {
isFetching: true,
isFailed: true,
isFetched: false
}
type Dd = {
isFetching: false,
isFailed: true,
isFetched: false
}
type Data = Aa | Bb | Cc | Dd
function thisWorks(data: Data): Data {
if (data.isFailed) {
return {
isFetching: true,
isFailed: true,
isFetched: data.isFetched
}
} else {
return {
isFetching: true,
isFailed: false,
isFetched: data.isFetched
}
}
}
function thisDoesNot(data: Data): Data {
return {
isFetching: true,
isFailed: data.isFailed,
isFetched: data.isFetched
}
}
is this bug or not?
Upvotes: 2
Views: 137
Reputation: 250396
The problem is that the object literal is compatible with neither Bb
or Cc
, since isFailed
is boolean
(since the field is common to all members of the union it will become true|false
which is boolean
)
The simplest solution is to use a type assertion to the union. This will preserve some checks but allow the assignment to occur:
function thisDoesNot(data: Data): Data {
return {
isFetching: true,
isFailed: data.isFailed,
isFetched: data.isFetched
} as Data
}
this would be an error:
function thisDoesNot(data: Data): Data {
return {
isFetching: 1,
isFailed: data.isFailed,
isFetched: data.isFetched
} as Data
}
We do lose excess property checks though, this would be valid:
function thisDoesNot(data: Data): Data {
return {
excess: 1,
isFetching: true,
isFailed: data.isFailed,
isFetched: data.isFetched
} as Data
}
Upvotes: 1