Home > Enterprise >  Narrowing Union Type of Set and Array for find method
Narrowing Union Type of Set and Array for find method

Time:01-12

I have the following Data model

Daily Data of a person

interface FetchDocument {
    Date : number,
    Hours : number,
}   

A collection of those data

type Data_Array = Set<FetchDocument> | FetchDocument[]

interface GroupDocument {
    name : string,
    Data : Data_Array,
   
}

A sample data for test is as follows

let fetchArray : GroupDocument[] = [
    {
        name : 'John',
        Data : [
            {
                Date : 13,
                'Hours' : 14
            },
            {
                Date : 12,
                'Hours' : 433
            }
        ] 
    }
]

When I want to find on that sample using find method

for(let i= 0; i < fetchArray.length ; i  ){
    let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )
}

The compiler is complaining as below because of Set Type on Data_Array.

error TS2339: Property 'find' does not exist on type 'Data_Array'.

Property 'find' does not exist on type 'Set'.

So what I have tried is try to narrow or re-assign to solve in three ways

Narrowing

 if(Array.isArray(fetchArray[i].Data)){
        let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )
 }
 if(typeof(fetchArray[i].Data.find) === 'function'){
        let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )
    }
   if(fetchArray[i].Data instanceof Array){
        let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )
    }

Re-assigning to array

fetchArray[i].Data = [...fetchArray[i].Data] 
let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )
fetchArray[i].Data = Array.from(fetchArray[i].Data.values())
let obj = fetchArray[i].Data.find((obj : FetchDocument) => obj.Date ===  13 )

But the error can't be solved so what can I do to resolve it.

Playground link : Link

Set is used when fetching data to detect duplicate data so changing it will cause for changing code on other part of codebase

CodePudding user response:

This is due what we call Temporal Uncertainty. Typescript doesn't know if there's any other codes changing the content of fetchArray that could lead to a different value while executing the code.

There is no need to explicit type assertion whatsoever, just save the value you wanna check in another variable as soon as you validate it

for (let i = 0; i < fetchArray.length; i  ){
    let arr = fetchArray[i].Data;
    if (arr instanceof Array) {
        let obj = arr.find((obj : FetchDocument) => obj.Date === 13)
    }
}

CodePudding user response:

You probably need to use Type Assertions in this case, but if the data is not an array, it will cause errors during runtime that's why you should also be careful about runtime errors.

Here is how you can do this,


for(let i= 0; i < fetchArray.length ; i  ){
    // treat data as a FetchDocument[] type note! it can be another type on run time
    const data = fetchArray[i].Data as FetchDocument[] 
    // consider use error handling here
    let obj = data.find((obj : FetchDocument) => obj.Date ===  13 )
}

Demo

Updated

You can also use Array.from method without adding any extra if

for(let i= 0; i < fetchArray.length ; i  ){
    let obj = Array.from (fetchArray[i].Data)
     .find((obj : FetchDocument) => obj.Date ===  13 )
}
  • Related