#Shouldn't TS catch that the object property may be undefined?

18 messages · Page 1 of 1 (latest)

carmine marsh
#

I am running this code and would love if TS was able to recognize that the object property may be undefined, but it doesn't. Instead the browser errors out.

const carInfo = {
  mercedes: {
    classification: 'luxury',
    color: 'blue',
    year: 2022,
  },
  lamborghini: {
    classification: 'sports',
    color: 'red',
    year: 1975,
  },
  tesla: {
    classification: 'electric',
    color: 'silver',
    year: 2015,
  }
}

const getCarInfo = (make: string) => {
  const car = carInfo[make];
  if (car.classification) {
    console.log('The classification is', car.classification)
  } else {
    console.log('Cant get the classification')
  }
}

When I try to call the function with an unsupported property such as getCarInfo('ford') , the browser errors out TypeError: Cannot read properties of undefined (reading 'classification'), which is what I expect, but I thought that TS would warn me that car may be undefined so I should access car.classification as car?.classification instead.

Is there any way I can make that happen in TS?

river pier
#

do you possibly have the strict flag disabled?

cedar frigateBOT
river pier
#

!ts

cedar frigateBOT
#
// 8<
const carInfo = {
  mercedes: {
    classification: 'luxury',
    color: 'blue',
    year: 2022,
  },
  lamborghini: {
    classification: 'sports',
    color: 'red',
    year: 1975,
  },
  tesla: {
    classification: 'electric',
    color: 'silver',
    year: 2015,
  }
}

const getCarInfo = (make: string) => {
  const car = carInfo[make];
//            ^^^^^^^^^^^^^
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ mercedes: { classification: string; color: string; year: number; }; lamborghini: { classification: string; color: string; year: number; }; tesla: { classification: string; color: string; year: number; }; }'.
//   No index signature with a parameter of type 'string' was found on type '{ mercedes: { classification: string; color: string; year: number; }; lamborghini: { classification: string; color: string; year: number; }; tesla: { classification: string; color: string; year: number; }; }'.
  if (car.classification) {
    console.log('The classification is', car.classification)
  } else {
    console.log('Cant get the classification')
  }
}```
river pier
#

because it errors on the default playground configuration

carmine marsh
#

Hmm, do you know what I put there? I was rather confused on how to solve that one.

river pier
#

yeah i have no clue...

#

... usually you can use narrowing if (!(make in carInfo)) { return; }

#

but that doesn't work when the type of make isn't a string literal type

#

(it still doesn't work if make has a generic type Make extends string)

carmine marsh
#

I see. Ok thanks. I'll play around with that

#

Appreciate your feedback

river pier
#

worst case i'd probably make a function that (unsoundly) returns T[keyof T] | undefined

cedar frigateBOT
river pier
#

!ts

cedar frigateBOT
#
// 8<
const carInfo = {
  mercedes: {
    classification: 'luxury',
    color: 'blue',
    year: 2022,
  },
  lamborghini: {
    classification: 'sports',
    color: 'red',
    year: 1975,
  },
  tesla: {
    classification: 'electric',
    color: 'silver',
    year: 2015,
  }
}

function unsafeTryGet<T>(it: T, k: PropertyKey): T[keyof T] | undefined {
    return (it as any)[k];
}

const getCarInfo = <K extends string>(make: K) => {
  const car = unsafeTryGet(carInfo, make);
  if (car?.classification) {
    console.log('The classification is', car.classification)
  } else {
    console.log('Cant get the classification')
  }
}```
river pier
#

(no errors)