I have interfaces like this
interface CatProps {
feedingTime: number,
color: string,
old: boolean
}
interface DogProps {
height: number,
breed: string,
allergies: boolean
}
interface Cat {
name: string,
data: CatProps[]
}
interface Dog {
name: string,
data: DogProps[]
}
type AnimalState = {
dog?: Dog[],
cat?: Cat[]
}
export interface AnimalStateEntries {
allStatesArrays: Dog[] | Cat[]
allStatesSingular: DogProps | CatProps
}
}
I then map through an object (ANIMALS) of type AnimalState like this, calling functionOne() and functionTwo()
const ANIMALS: AnimalState = {...}
(Object.keys(ANIMALS) as Array<keyof AnimalState >).map((identifier, index) => {
let animal = ANIMALS[identifier]
if(animal) {
let {name, data} = animal
functionOne(name, data, identifier)
}
})
const functionOne = (name: string, data: AnimalStateEntries['allStatesArray'], identifier: keyof AnimalState) => {
return data.map(information => functionTwo(information, identifier)
})
const functionTwo = (data: AnimalStateEntries ['allStatesSingular'], identifier: keyof AnimalState) => {
if(identifier === 'dog') {
const {height, breed, allergies} = data
} else {
const {feeding, color, old} = data
}
}
But, when I try to access const {height, breed, allergies} = data and const {feeding, color, old} = data in functionTwo() I am getting
Property ‘…’ does not exist on type ‘CatProps | DogProps   Property ‘…’ does not exist on type ‘DogProps’.
Where ... are the props I am trying to access.
If I change const functionTwo = (data: any, identifier: keyof AnimalState) => {...}
It works. Why is that?
>Solution :
if(identifier === 'dog') {
gives Typescript no idea about the type of data. You will have to use some type narrowing which typescript understands.
Try to use a type predicate:
function isDog(identifier: 'dog' | 'cat', data : AnimalStateEntries ['allStatesSingular']): data is DogProps {
if(identifier === 'dog')
return true;
return false;
}
Change your if condition like:
if(isDog(identifier,data)) {
const {height, breed, allergies} = data
}