Lavariet
Lavariet

Reputation: 635

How to assign an interface / type to a variable based on a condition in Typescript

I would like to set the type / interface of a variable based on a condition. If possible I would like no reassignment of the variable.

comment1 for below code:

setting the type to responseData: typeA | typeB = response.data here results in Errormessage "Property 'specificBValue' does not exist on type 'typeA'.ts(2339)" or the other way around Property 'specificAValue' does not exist on type 'typeB'

interface typeA {
  name: string
  specificAValue: number
}

interface typeB {
  name: string
  specificBValue: string
}

const targetType = userInput.targetType;
axios.get(`/api?target=${targetType}`)
  .then(response => {
    const responseData = response.data; // comment1
    if(targetType === "A") {
      responseData: typeA
      console.log(responseData.specificAValue);
    } else if(targetType === "B") {
      responseData: typeB
      console.log(responseData.specificBValue);
    } else ...

Upvotes: 0

Views: 1017

Answers (1)

Denis Frezzato
Denis Frezzato

Reputation: 968

What you need is a way to narrow down the type of responseData. You can use type guards. See also this.

interface TypeA {
  name: string
  specificAValue: number
}

interface TypeB {
  name: string
  specificBValue: string
}

declare const responseData: unknown

const isUnknownRecord = (u: unknown): u is Record<string, unknown> => {
  const s = Object.prototype.toString.call(u)
  return s === '[object Object]' || s === '[object Window]'
}

const isString = (u: unknown): u is string => typeof u === 'string'

const isNumber = (u: unknown): u is number => typeof u === 'number'

const hasOwnProperty = Object.prototype.hasOwnProperty

const isTypeA = (u: unknown): u is TypeA =>
  isUnknownRecord(u) &&
  hasOwnProperty.call(u, 'name') &&
  isString(u.name) &&
  hasOwnProperty.call(u, 'specificAValue') &&
  isNumber(u.specificAValue)


const isTypeB = (u: unknown): u is TypeB =>
  isUnknownRecord(u) &&
  hasOwnProperty.call(u, 'name') &&
  isString(u.name) &&
  hasOwnProperty.call(u, 'specificBValue') &&
  isString(u.specificBValue)

if (isTypeA(responseData)) {
  responseData // TypeA
} else if (isTypeB(responseData)) {
  responseData // TypeB
}

Playground

I suggest you to not reinvent the wheel and use libraries like io-ts.

Upvotes: 1

Related Questions