Home > other >  Why am I getting a "Property 'X' does not exist on type 'Y' when Y has an i
Why am I getting a "Property 'X' does not exist on type 'Y' when Y has an i

Time:01-08

type JSONValue =  string | {[x:string]:string}

function foo(p:JSONValue){
    console.log(p.aaaa);
}

the compiler says:

Property 'aaaa' does not exist on type 'JSONValue'. Property 'aaaa' does not exist on type 'string'.ts(2339)

but this compiles:

type JSONValue =  {[x:string]:string}

function foo(p:JSONValue){
    console.log(p.aaaa);
}

why? how to fix?

CodePudding user response:

The problem here is because when you're console logging, the compiler doesn't know if 'p' is a dictionary or a string. If it knew that it wasn't a string then it would compile correctly. The reason for this is because a string doesn't have the property 'aaaa'.

The way you would do this is:

type JSONValue =  string | {[x:string]:string}
function foo(p:JSONValue){
    if (typeof p != "string") {
        console.log(p.aaaa);
    }
}

CodePudding user response:

At the line that triggers the error, p is known to be a JSONValue, which could be either a string or an object with a [x:string]:string index signature. If it were a string, then indeed it wouldn't have an aaaa property. That is essentially what the error is telling you.

For example, in the following the first console.log call won't generate an error because both string and {[x:string]:string} have the property length. Only the second log call will have the error:

type JSONValue = string | { [x: string]: string }

function foo(p: JSONValue) {
    console.log(p.length)
    console.log(p.aaaa)
}

solution: type narrowing

Clearly you want to access the property aaaa from p ONLY IF p is a {[x:string]:string}, not if it is a string, right?. So put that logic in your code! Like this:

function foo(p: JSONValue) {
    if (typeof p === 'string') {
        // Typescript knows p has type string within this block
    } else {
        // Typescript knows p is not a string, and thus
        // by process of elimination must be a
        // { [x: string]: string } within this block
        console.log(p.aaaa)
    }
}

or like this:

function foo(p: JSONValue) {
    if (typeof p === 'object') {
        console.log(p.aaaa)
    }
}
  •  Tags:  
  • Related