Daniel Grace
Daniel Grace

Reputation: 101

"Property ... does not exist on type ..." error when using Typescript

I get the error when compiling a file with typescript:

Property 'qaz' does not exist on type '{ bar: string; }'.

With the following code in the file:

let foo = {
    bar: "Can you perform a Quirkafleeg?"
}

let { qaz = "I'm feeling manic!" } = foo;
console.log(qaz);
console.log(qaz.bar);

Based on example code on the page: https://zellwk.com/blog/es6/ in the section "Destructuring objects".

I was expecting to get the second string as output, but I'm a bit confused as there is another example on that page along the lines of:

let { fizz: faz = "Eugene was my friend." } = foo; // as defined above
console.log(fizz);
console.log(fizz.faz);

Which gives a similar error:

Property 'fizz' does not exist on type '{ bar: string; }'.

Upvotes: 9

Views: 18980

Answers (3)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249656

The article is about ES destructuring, which is also implemented in typescript. Typescript will however perform extra checks. One of those checks is that you can't destructure from a type that does not declare the property.

So, this will be an error:

let foo = {
    bar: "Can you perform a Quirkafleeg?"
}

let { qaz = "I'm feeling manic!" } = foo; //err

While this will work:

let foo = {
    bar: "Can you perform a Quirkafleeg?",
    qaz: undefined
}

let { qaz = "I'm feeling manic!" } = foo; //ok qaz is "I'm feeling manic!" because of the default

Or you can specify the type explicitly:

let foo: { bar: string, qaz?: string} = {
    bar: "Can you perform a Quirkafleeg?",
}

let { qaz = "I'm feeling manic!" } = foo; //ok qaz is "I'm feeling manic!" because of the default

The other part is you can destructure a property to a variable of a different name, so below, we take bar from foo and put in fizz

let foo = {
    bar: "Can you perform a Quirkafleeg?",
    qaz: undefined
}
let { fizz: bar = "Eugene was my friend." } = foo; // basically same as let fizz = foo.bar || "Eugene was my friend."
console.log(fizz); // "Can you perform a Quirkafleeg?" 

But the same typescript restriction applies, that bar in this case must be defined on foo.

This is generally the extra layer of type checking typescript does, you can't access properties typescript does not know about, either through destructuring or direct access with . or []

The last part, accessing console.log(fizz.faz); will never be valid, fizz is not the original object, it is the string that was in foo.bar, so it will not have a property faz or bar. I believe this is a misunderstand of the source blog on your part, I did not find any such claim in the blog.

Upvotes: 4

Murat Karagöz
Murat Karagöz

Reputation: 37594

That is working as expected. You are destructing and providing a default parameter to qaz. It should work, but it seems like the tscompiler has an issue with that. You can fix it by providing the type any e.g.

  let foo = { bar: "Can you perform a Quirkafleeg?" }
  let { qaz = "I'm feeling manic!" }: any = foo;
  console.log(qaz); // I'm feeling manic!
  console.log(qaz.bar); // undefined

Upvotes: 2

Andrei
Andrei

Reputation: 1216

That's not how Destructuring objects work.

Essentially it will look at the child properties of foo and assign new variable to them

That must match the property names of foo

For instance

const Zell = {
  firstName: 'Zell',
  lastName: 'Liew'
}

let { firstName, lastName } = Zell

console.log(firstName) // Zell
console.log(lastName) // Liew

to fix your example you'll need to do

let foo = {
    bar: "Can you perform a Quirkafleeg?"
}

let { bar } = foo;
console.log(bar);

When you try to access 'qaz' on bar it cannot since bar is a String

EDIT:

To expand in your example

let { qaz = "I'm feeling manic!" } = foo; When you're assigning qaz a value via = it is actually just a default value if it is not found on the object foo.

In your example

let { fizz: faz = "Eugene was my friend." } = foo; you're trying to assign fizz to the value of foo.faz and if fizz does not exist on foo it will default to "Eugene was my friend."

Upvotes: 1

Related Questions