Reputation: 1481
I'm using Typescript with React.
I am retrieving data from an API that returns two type: VirtualMachine
or Disk
. The backend takes responsibility for distinguishing the resource type and returns the type of both depending on the results of the query:
requestMoreInfo: (resourceType: string, resourceId: number): AppThunkAction<ResourceActions> => (dispatch, getState) => {
let fetchResourceInfo = fetch('http://localhost:5004/GetResourceTypeInformation/' + resourceType + '/' + resourceId, {
method: 'GET'
})
I've declared a union type for my Redux state:
export interface ResourceState {
currentResourceInformation?: VirtualMachineInformation | DiskInformation;
}
and I am subsequently converting the response to the type determined by the resource type passed into the function and dispatching an action to update my components state. THIS IS WHERE I THINK I'M GOING WRONG.
if (resourceType == "Virtual Machine") {
var vmResponse = response.json() as VirtualMachineInformation;
dispatch({
type: 'RECEIVE_RESOURCE_INFO',
resourceInfo: vmResponse
});
}
else if (resourceType == "Disk") {
var diskResponse = response.json() as DiskInformation;
dispatch({
type: 'RECEIVE_RESOURCE_INFO',
resourceInfo: diskResponse
});
}
TypeScript appears to be happy with this. However, I am then trying to render a child component and passing this update state as a prop:
private requestResourceInformation = (resourceType: string, resourceId: number) => {
this.props.requestMoreInfo(resourceType, resourceId);
if (resourceType == "Virtual Machine") {
return <VirtualMachineResource virtualMachine={this.props.currentResourceInformation} />
}
}
This just maps a table with the data.
However, I'm retrieving the error:
Type 'VirtualMachineInformation | DiskInformation | undefined' is not assignable to type 'VirtualMachineInformation | undefined'.
Type 'DiskInformation' is not assignable to type 'VirtualMachineInformation | undefined'.
Type 'DiskInformation' is not assignable to type 'VirtualMachineInformation'.
Property 'azureVmId' is missing in type 'DiskInformation
I believe this is because TypeScript still considers the value as the union type and the expected value is present in VirtualMachine
type but no present in the Disk
type.
Where am I going wrong with this? Is there an explicit way to declare the specific type of the union after retrieving the data?
Upvotes: 0
Views: 1195
Reputation: 2564
The virtualMachine
property doesn't accept the DiskInformation
interface as a value - and that is your problem. TypeScript compiler doesn't know what's the exact type of the value at the compile time so the type is guessed to be one among those three: VirtualMachineInformation
, DiskInformation
, undefined
As I wrote in the comments section - you can use (at least) three solutions to solve your problem:
use type assertions - https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions - you can not use <Type>value
syntax in tsx files
return <SomeComponent prop={value as Type}></SomeComponent>
use type guards https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards
if ([check if type of the value is the Type]) {
return [something else]
}
[TypeScript knows that the value IS NOT an instance of the Type here]
return <SomeComponent prop={value}></SomeComponent>
use overloads - http://www.typescriptlang.org/docs/handbook/functions.html#overloads
class X {
private y(x: "abc"): "cda";
private y(x: "cda"): "abc";
private y(x: string): string {
[method logic]
}
}
Upvotes: 2