I am working on converting an JS application to typescript and have encountered an issue where the data structure is as follow:
{
id: '46528ed4-1dd7-4d37-b92b-0f1c79dcf92f', // Some guid
version: 1, // Representing the version og the content
'104d56d7-f367-46f0-b107-06ebdcd07a4d': { // These objects are fetched from an api and i have no knowledge og what the guid strings that are used to index are
id: 1,
html: '<p>Hi</p>' // Some stringified html
},
'25c95291-1836-4b01-a537-20223bab1688': {
id: 2,
html: '<p>Bye</p>' // Some stringified html
}
}
So i created the interfaces:
interface ResponseWrapper {
id: number,
html: string,
}
interface ApiResponse{
id: string,
version: number | null,
[key: string]: ResponseWrapper | string | number | null,
}
Note that i have to add the | string | number | null
to not get the error Property 'id' of type 'string' is not assignable to 'string' index type 'ResponseWrapper
Now when i want to access the html i have a list of guids which is fetched from another api:
const ids = ['someId', 'someOtherId']; // gotten from an api
const apiResonsone = getData() as ApiResponse // some allready which is of the type ApiResponse fetched data
const htmlList = ids.map(id => apiResonsone[id].html)
Here i get the error Property 'html' does not exist on type 'string | number | ResponseWrapper'.
I would like to know how this should be typed, i do not have access to change the data structure as my task is only to convert the JS code to Typescript.
Thank you for any responses.
CodePudding user response:
You are already off to a bad start with:
Note that i have to add the
| string | number | null
to not get the errorProperty 'id' of type 'string' is not assignable to 'string' index type 'ResponseWrapper
It undermines the point of type safety if you hack the type declarations just to get rid of error messages rather than figuring out the appropriate type declarations.
I understand why you did it. There's no way to say that the index signature type doesn't apply to id
and version
.
Oh wait... in this case you're in luck... There is a way since the guid's have a pattern which sets them apart from id
and version
:
Using Template String Pattern Index Signatures
With this new feature introduced by Typescript 4.4, we can more strongly type the ApiResponse
GUID keys. While the guid
type below doesn't enforce all the rules of a GUID string pattern, it does require it to have five segments separated by dashes:
type guid = `${string}-${string}-${string}-${string}-${string}`
interface ApiResponse{
id: string,
version: number,
[key: guid]: ResponseWrapper
}
interface ResponseWrapper {
id: number,
html: string,
}