Skip to content

Optional Chaining and Type Narrowing #48748

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ghost opened this issue Apr 18, 2022 · 2 comments
Closed

Optional Chaining and Type Narrowing #48748

ghost opened this issue Apr 18, 2022 · 2 comments

Comments

@ghost
Copy link

ghost commented Apr 18, 2022

πŸ”Ž Search Terms

Optional Chaining, as Operator, Type Narrowing

πŸ•— Version & Regression Information

v4.6.2, 'Nightly' version as well

⏯ Playground Link

https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgtgQwObQLxQN4CgpQGYD2ATosAM4BcUZwRAlgHZIDaAumwNxYC+WWokKAAUiBACYBXAMbAo6bLjqIUlWMohsoAHygMJAG31de-cNACCUqRDJliIOZhMCLYsQQaOFUMKMkyqEXFpWR1La1t7bV0DIx4+PAkGGToPKCkACwgpAGsACgQ3D1VzIoY2AEpMHCg6PCg8grKyZgAGVgB+ADpfYJkoBDJhPxCK7qVkG279CCZgDKrvXCli2Tw6Ihp4Sccm9wYW9p6R-sHhvuAKromVNtYuXF5uIA

πŸ’» Code

type Image = {
  formats: string[][];
}

type Product = {
  images: Image[] | null;
}

type Accessory = {}

type Addon = {
  product: Product | Accessory | null;
}

function check(addons: Addon[]) {
  if ((addons[0]?.product as Product)?.images?.length) {
    const firstImage = (addons[0].product as Product).images[0];
  }
}

πŸ™ Actual behavior

Errors in code: Object is possibly 'null'

πŸ™‚ Expected behavior

No errors

Additional note

If you remove 'Accessory' type at all and remove the 'as' operator, everything will work fine

@MartinJohns
Copy link
Contributor

MartinJohns commented Apr 18, 2022

Narrowing only occurs on specific syntax. By using a type assertion the compiler is losing the context to the variable and can't narrow it anymore. You can narrow a variable, such as addons[0]?.product, but you can't narrow an expression like addons[0]?.product as Product. I'm sure I've seen an issue about this already, but I can't find it anymore right now. (edit: Semi related: #34974 (comment))

A simple workaround is to store type-asserted value in a variable and then narrow the variable:

const product = addons[0]?.product as Product | undefined;
if (product?.images?.length) {
  const firstImage = product.images[0];
}

Side-note: The {} type does not mean an object without any properties. I hope you're aware of this.

@ghost
Copy link
Author

ghost commented Apr 18, 2022

Thanks for clarification @MartinJohns . Close the issue

@ghost ghost closed this as completed Apr 18, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant