Skip to content

feat: articles on string types and object type inferences - #31

Closed
JoshuaKGoldberg wants to merge 4 commits into
mainfrom
first-two-articles
Closed

JoshuaKGoldberg wants to merge 4 commits into
mainfrom
first-two-articles

Conversation

@JoshuaKGoldberg

@JoshuaKGoldberg JoshuaKGoldberg commented May 31, 2022 •

Copy link
Copy Markdown
Collaborator

Overview

Sending these two in a single PR for now as one references the other. Will likely split out.

Comment thread docusaurus.config.js Outdated
Comment thread src/content/articles/objects-narrowed-before-usage.mdx
Comment thread src/content/articles/objects-narrowed-before-usage.mdx Outdated
Comment thread src/content/articles/objects-narrowed-before-usage.mdx
@JoshuaKGoldberg JoshuaKGoldberg changed the title ✨ feat: [WIP] first two articles [WIP] ✨ feat: articles on string types and object type inferences Jun 4, 2022
@JoshuaKGoldberg JoshuaKGoldberg changed the title [WIP] ✨ feat: articles on string types and object type inferences feat: articles on string types and object type inferences Feb 21, 2023
Comment on lines +9 to +11
Why does TypeScript report a `string` type instead of `keyof typeof` the object when you use a `for...in` loop or `Object.keys()` on an object?

One of the most commonly asked questions in TypeScript help forums is why code like the following gives an error under the [`noImplicitAny` compiler option](https://www.typescriptlang.org/tsconfig#noImplicitAny).

@CBID2 CBID2 Jul 27, 2023 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nitpick/proofreading] Hmmm..., there seems to be some ambiguity in this part of your article. Maybe you can try the suggestion below to make it clearer.

Suggested change
Why does TypeScript report a `string` type instead of `keyof typeof` the object when you use a `for...in` loop or `Object.keys()` on an object?
One of the most commonly asked questions in TypeScript help forums is why code like the following gives an error under the [`noImplicitAny` compiler option](https://www.typescriptlang.org/tsconfig#noImplicitAny).
One of the most commonly asked questions in TypeScript help forums is why code like the one below gives an error under the [`noImplicitAny` compiler option](https://www.typescriptlang.org/tsconfig#noImplicitAny).

TypeScript's type system is _structurally typed_: meaning any value that happens to satisfy a type is allowed to be used as a value of that type.
In other words, when you declare that a value is of a particular object type, you're telling TypeScript any object that just so happens to have those properties is allowed to be considered that type.

As a result, when you write a `for...in` loop over the keys of an object, you often won't have a guarantee that the object's keys will only be from the type of the object.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick/proofreading] This paragraph could be a bit clearer. The first introductory phrase (As a result) creates a repetitive flow because the other phrase "when you write" conveys the same idea.

Suggested change
As a result, when you write a `for...in` loop over the keys of an object, you often won't have a guarantee that the object's keys will only be from the type of the object.
As a result, writing a `for...in` loop over the keys of an object won't often guarantee that the object's keys will only be from the type of the object.

In other words, when you declare that a value is of a particular object type, you're telling TypeScript any object that just so happens to have those properties is allowed to be considered that type.

As a result, when you write a `for...in` loop over the keys of an object, you often won't have a guarantee that the object's keys will only be from the type of the object.
Some other area of code might have provided an object with more properties that just so happens to match the structural type.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading] Since this sentence is describing other parts of the code, consider turning "area" into a plural noun to convey this idea clearly.

Suggested change
Some other area of code might have provided an object with more properties that just so happens to match the structural type.
Some other areas of code might have provided an object with more properties that just so happens to match the structural type.

Needing to wrestle with the type checker is often a byproduct of application code going against safe JavaScript practices -- such as the aforementioned issues with `for...in` loops receiving unexpected key strings.
In many cases, it might be good to listen to TypeScript and consider refactoring your code to use a JavaScript API better suited to the task.

If all your code needs to do is get all the values in an object, an `Object.values()` API exists that returns those as an array.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading/nitpick/question] I edited the sentence a bit to make it clearer. Is the below suggestion the message you want to convey?

Suggested change
If all your code needs to do is get all the values in an object, an `Object.values()` API exists that returns those as an array.
If all your code needs all an object's values, an `Object.values()` API exists to return those as an array.

Taking an even larger step back, why is the application code looping over an object's keys and values?
Is the object meant to be used as a general key-value store?

If so: consider using the built-in `Map` data structure instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading/typo] It's always best to use a comma for introductory elements.

Suggested change
If so: consider using the built-in `Map` data structure instead.
If so, consider using the built-in `Map` data structure instead.

### Type Assertions

Still, there are times when a `for...in` loop or `Object.keys()` might likely be mostly safe to use for object keys.
If you are 100% absolutely completely sure that your use case won't crash from some bizarre type mismatch now or in the future, you can always use an `as` assertion to cast the loop variable to the right type.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading/nitpick] While mentioning "completely" and "absolutely" encourages devs to think deeply about the use case, I think saying "100% sure" conveys this point perfectly.

Suggested change
If you are 100% absolutely completely sure that your use case won't crash from some bizarre type mismatch now or in the future, you can always use an `as` assertion to cast the loop variable to the right type.
If you are 100% sure that your use case won't crash from some bizarre type mismatch now or in the future, you can always use an `as` assertion to cast the loop variable to the right type.

TypeScript's type system boasts a feature called _type narrowing_.
Type narrowing means that if a block of code can only be reached when a value is a specific type, then the value will be considered that type inside the block.

As an example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading] Hmmm...I think using "for" instead of "as a" would make the sentence clearer.

Suggested change
As an example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.
For example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.

### A Practical Example

Let's say you want to `console.log` the `counts` object before reassigning a new value to a count.
Your use your own custom `log` function that just so happens to only call `console.log`?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Nitpicking/proofreading/question] This part seems more like statement. Did you mean to make it a question?

Suggested change
Your use your own custom `log` function that just so happens to only call `console.log`?
But your use your own custom `log` function that just so happens to only call `console.log`.

TypeScript's type system boasts a feature called _type narrowing_.
Type narrowing means that if a block of code can only be reached when a value is a specific type, then the value will be considered that type inside the block.

As an example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Proofreading] Seems similar to this part in the other article.

Suggested change
As an example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.
For example, take the following `fruit` variable of type `string | undefined` (a union type indicating it can be either `string` or `undefined`.

@CBID2 CBID2 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @JoshuaKGoldberg! :) I added some in-line comments on how you can improve your articles grammar-wise. Other than that, You're are off to a great start! Good job! 😄 👍🏾

@JoshuaKGoldberg

Copy link
Copy Markdown
Collaborator Author

@CBID2 thanks for looking at this. It's a very old draft I'm not likely to pick up any time soon though. I wouldn't recommend giving reviews on any old blog drafts of mine. Some of them last for months or years before I close or drastically rewrite 😄

@CBID2

CBID2 commented Jul 27, 2023

Copy link
Copy Markdown

@CBID2 thanks for looking at this. It's a very old draft I'm not likely to pick up any time soon though. I wouldn't recommend giving reviews on any old blog drafts of mine. Some of them last for months or years before I close or drastically rewrite 😄

Ah ok @JoshuaKGoldberg. Well, if you ever change your mind, they're there lol 😂

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

Successfully merging this pull request may close these issues.

2 participants