Revanth M
Revanth M

Reputation: 113

Unable to get typescript typings to match

I am unable to get the following code to work.

I am trying to fetch some data and handling all the falsy/error cases and then passing on the cleaned data to another function. But the typings don't seem to match when I call the second function.

Type 'Error | number[]' is not assignable to type 'number[]'

interface SomeType {
  a: number[] | null | Error
  b: number[] | null
}

type Omit <T, K> = Pick<T, Exclude<keyof T, K>>
type ExcludeUnusableValues<T,K extends keyof T,C = Error | null>
  = Omit<T, K> & {
    [a in K]-? : Exclude<T[a], C>
  }

function fetchData() {
  const obj: SomeType = {
    a: [1, 2, 3],
    b: null
  }
  if (obj.a === null || obj.a instanceof Error) {
    return null
  }

  //  Type 'Error | number[]' is not assignable to type 'number[]'
  useData(obj)
}

function useData(param1: ExcludeUnusableValues < SomeType, 'a' > ) {
  console.log(param1)
}

TypeScript playground link

Upvotes: 2

Views: 131

Answers (2)

Bijou Trouvaille
Bijou Trouvaille

Reputation: 9484

You can work around the issue by moving your type checking logic into a type predicate. Here is your example, modified with isUsableType:

interface SomeType {
  a: number[] | null | Error
  b: number[] | null
}

function isUsableType(obj: SomeType): obj is ExcludeUnusableValues < SomeType, 'a' > {
  return obj.a!==null && !(obj.a instanceof Error)
}

type Omit <T, K> = Pick<T, Exclude<keyof T, K>>
type ExcludeUnusableValues<T,K extends keyof T,C = Error | null>
  = Omit<T, K> & {
    [a in K]-? : Exclude<T[a], C>
  }

function fetchData() {
  const obj: SomeType = {
    a: [1, 2, 3],
    b: null
  }

  if (isUsableType(obj)) {
    useData(obj)
  } else return null;

}

function useData(param1: ExcludeUnusableValues < SomeType, 'a' > ) {  
  console.log(param1)
}

Upvotes: 1

Shadab Faiz
Shadab Faiz

Reputation: 2508

Short Answer: Remove type Error from SomeType.a.
Long Answer:

a: number[] | null;

a can be either array of number or null. It is perfectly fine because either a exits or it doesn't.

a: number[] | null | Error;

Here, type Error is causing problem because Error does not have same property/functions that array of number has. For this to work, all the types must have some similar properties.

Another solution: Typecast the obj to appropiate type:

useData(<{a: number[], b: number[]}>obj)

Upvotes: 0

Related Questions