Skip to content

Stop using "any" in the JS declarations #56618

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
coolCucumber-cat opened this issue Nov 30, 2023 · 32 comments
Closed

Stop using "any" in the JS declarations #56618

coolCucumber-cat opened this issue Nov 30, 2023 · 32 comments

Comments

@coolCucumber-cat
Copy link

πŸ”Ž Search Terms

any, unkown

πŸ•— Version & Regression Information

Here it says in the TS docs:
"❌ Don’t use any as a type unless you are in the process of migrating a JavaScript project to TypeScript. The compiler effectively treats any as β€œplease turn off type checking for this thing”. It is similar to putting an @ts-ignore comment around every usage of the variable. This can be very helpful when you are first migrating a JavaScript project to TypeScript as you can set the type for stuff you haven’t migrated yet as any, but in a full TypeScript project you are disabling type checking for any parts of your program that use it.

In cases where you don’t know what type you want to accept, or when you want to accept anything because you will be blindly passing it through without interacting with it, you can use unknown."

So why are there so many anys all over the codebase? If you're not going to use generics, at least use unknown. Yeah it might break something that was already working, but isn't that kinda the point? To make bad code not be allowed? And it's just TS, it won't actually break real code.

⏯ Playground Link

No response

πŸ’» Code

JSON.parse("1") // number, or unknown
[1].values().next().value // number
Array(1) // a generic, defaults to unknown

πŸ™ Actual behavior

JSON.parse("1") // any
[1].values().next().value // any
Array(1) // any[]

πŸ™‚ Expected behavior

JSON.parse("1") // number, or unknown
[1].values().next().value // number
Array(1) // a generic, defaults to unknown

Additional information about the issue

No response

@coolCucumber-cat coolCucumber-cat changed the title Stop using "any" in thr Stop using "any" in the JS declarations Nov 30, 2023
@MartinJohns
Copy link
Contributor

Duplicate of #26188, and probably a few others (as this "bug report" is very unspecific).

@fatcerberus
Copy link

it's just TS, it won't actually break real code

I'm sure TypeScript devs everywhere will be happy to learn they haven't been writing real code all this time 🀣

@coolCucumber-cat
Copy link
Author

@MartinJohns What else is it then? The docs are saying you should never do this and then it does that in code that everyone will use. Using just one of the functions included in the standard library can leak anys everywhere if you're not careful. And it's a very unspecific issue, am I supposed to make an issue for each one? Because there are a huge amount of them everywhere.

@coolCucumber-cat
Copy link
Author

@fatcerberus Yeah, I'm one and it isn't. I don't see any browsers or runtimes running TypeScript. Bun? That turns TypeScript into JavaScript, because it can't run TypeScript.

@fatcerberus
Copy link

Yeah, I'm one and it isn't. I don't see any browsers or runtimes running TypeScript. Bun? That turns TypeScript into JavaScript, because it can't run TypeScript.

If you think the fact that nothing runs TypeScript "natively" means TS can just introduce massive breaking changes and add new compiler errors to people's code willy-nilly, then yeah, this isn't worth engaging with further.

@MartinJohns
Copy link
Contributor

MartinJohns commented Nov 30, 2023

Software development is not black and white. There's not the one true statement for every case. The documentation is a general guideline.

It's also a question of practicality. Changing this is a massive breaking change. And in some cases the any just makes more sense (e.g. for JSON.parse(), which is inherently type unsafe).

And it's a very unspecific issue, am I supposed to make an issue for each one?

That would be more practical than "don't use any anywhere". In some cases it's part of the declaration file (e.g. JSON.parse(), for which there exists many issues), and in another case you're talking about the fallback to any if a type can't be resolved (there exists an issue too).

And you can be assured that the type is very well away of issues revolving around any and tries to eliminate it, within reason.

@coolCucumber-cat
Copy link
Author

@fatcerberus

TLDR: preventing bugs is really bad and the world will explode.

Ok, and what's so bad about these breaking changes? Does it somehow make things not work anymore? Will every website on the internet crash? Will the issue be really hard to fix? Will it be a change that makes no sense? Will it make anything, at all, worse? It doesn't? Oh, it's now following the rules set forth by the docs? And it behaves as expected? And it will make the code more understanderable? And it will prevent bugs? And it's doing what TypeScript is supposed to do? If you're so ok with anys everywhere, why don't you just use it everywhere? Hell, why do even use TypeScript? Oh no, we're fixing a bug and some poeple might have to put in a little bit of effort so that their code works as they expected it to. "Willy-nilly". If you think that's "willy-nilly", you're not worth engaging with further. How do you not understand these basic TypeScript things? "breaking changes". This isn't Python, which also doesn't run natively, this will just prevent people from compiling their code. You still have the old code and that code still works. Nothing actually breaks. Here's the worst case scenario: there's a bug in the codebase. there's a change that prevents this bug. you might have to change your code to fix the bug. oh no, i had to fix a bug. literally the worst thing that can happen to you is that you have to fix a small bug. so terrible.

I can't remember what you said last time I interacted with you, but if I was in charge of a big tech company, I'd make you be a manager.

@coolCucumber-cat
Copy link
Author

@MartinJohns

I see you've read what I said to the other guy. This prevents people from writing bugs. You know what's a breaking change? "Uncaught TypeError: Cannot read properties of null (reading 'value')". No, any never makes sense. If it's so unsafe, then why is ok for it to be unsafe without any warnings whatsoever? If it's so unsafe, make it be unknown. In case you didn't know, unknown means you don't know what it is. Like what possible reason could you have for not at least making it be unknown? You keep saying random substanceless corporate gibberish.

Why is it that whenever I speak to either of you, you both say the fucking stupidest things? "no preventing bugs is bad". "no it's not black and white". "oh no, we can only get rid of any within reason", "no it's just a general guideline". Man I could say 1 + 1 is 2 and you both would leave a comment other than saying yes. "if we made 1 + 1 be 2, it would break so much code. we can only make calculations be correct within reason. yeah i know not fixing this caused a hospital to blow up, but it would theoretically be possible that this change might accidently fix world hunger. I know this is breaking international laws and the Geneva convention, but those are just recommendations anyway. so if you make an indivual bug report for each any in the codebase, i will consider it (meaning i won't). that's because i somehow don't understand what TS is or how that preventing bugs is a good thing".

@coolCucumber-cat
Copy link
Author

@fatcerberus @MartinJohns

Preventing bugs is a bad thing right?

@fatcerberus
Copy link

Yeah, this is getting out of hand. I fully expect @RyanCavanaugh (the project lead) to lock this issue whenever he gets around to reading it.

I'm just going to leave this here
https://opensource.microsoft.com/codeofconduct/

@coolCucumber-cat
Copy link
Author

@fatcerberus

Oh no, someone doesn't agree with me and they're right! This is out of hand!

Tell me, what are the consequences of fixing this? Like what is the worst thing that could happen from fixing this? Don't tell me how this is a breaking change, what will happen from it being a breaking change?

@somebody1234
Copy link

@coolCucumber-cat hey, just pointing out that browsers can't run JS either! they actually run machine code

@coolCucumber-cat
Copy link
Author

@somebody1234

Are you 3 intentionally trolling? It's not relevant and you keep bringing it up for no reason. Neither do you understand it.

The TypeScript bit of the code literally doesn't do anything. You can't print to the console, you can't add numbers, you can't have variables, it doesn't affect anything in the code. That's also in the docs. No TS should affect in the JS.

Why is this so difficult for you all to understand?

Are you trying to tell me if I put machine code in the script tag, it will do anything? Actually, they run with electricity.

@somebody1234
Copy link

right, sorry, my bad... regardless, it's still true that browsers don't run JS - they turn it into a bytecode format first, which is what gets executed. JS can't print to the console, JS can't add numbers, JS doesn't have variables - it's all the bytecode instructions (and the underlying C++ implementation of each method, depending on the methods).

IOW: just like how bun transpiles TS to JS in a just-in-time manner, the browser transpiles JS to machine code in a just-in-time manner (and the bytecode down to machine code as well). so i'm interested in learning what is the difference between zig doing the JITting (bun), rust doing the JITting (deno) and C++ doing the jitting (V8, JSCore)

@coolCucumber-cat
Copy link
Author

@fatcerberus I haven't broken the code of conduct. It can't be, for example, not accepting constructive critisism, there isn't any. If all the critisism, you, Martin and Ryan have given me was constructive, I could have invented teleportation. You can never actually tell me what would be so bad about preventing these bugs, you just make up reasons for it.

@coolCucumber-cat
Copy link
Author

@somebody1234 I can't believe I have to re-explain this thing that should not have to be explained in the first place.

I propose to prevent people from writing bugs. This may break people's code and they may have to fix it because their buggy code is not allowed anymore, which is a good thing and that is what TS is for. However, that does not affect anything, at all. An example of a breaking change would be to make console.log make your computer blow up. This change simply prevents people from compiling bad code. You're clearly intentionally misunderstanding what I said. TS literally does not do anything. It literally disappears when you compile it. JS can do things. Ok it doesn't have variables, but I can actually do things with it on my computer.

TS literally does not do anything.

You are definitly trolling at this point, you misunderstand the most basic points and say "actually, variables don't exist" . "1 + 1 isn't 2, numbers are just made up". Sure, they are. But 1 + 1 is still 2.

@MartinJohns
Copy link
Contributor

I haven't broken the code of conduct.

From the Code of Conduct:

Examples of unacceptable behavior include:

  • Trolling, insulting or derogatory comments, and personal or political attacks

For example:

Why is it that whenever I speak to either of you, you both say the fucking stupidest things


And lastly, a clarification on what "breaking change" in the context of TypeScript means: Compiled with the previous version and reports compilation errors with the new version, or compiles to new JS code with different runtime behavior. This aligns with the "Breaking Changes" section of the release notes, issues labelled as "Breaking Change" and what I have observed over the many many years.

@somebody1234
Copy link

@coolCucumber-cat again, my point is that JS disappears when you compile it as well. you cannot do things with it on your computer because it disappears when it is compiled to bytecode

@coolCucumber-cat
Copy link
Author

@MartinJohns You gave my comment a dislike, but you never explained how it actually affects anything.

That's why I said "you say the stupidest things", not... no I'm not going to say what would have been bad, because I can imagine that backfiring somehow.

It literally is a stupid thing, that's not an insult. If someone says the earth is flat, am I not allowed to call that stupid? Especially when it definitly is?

Let's say there's a version of TypeScript that just allows anything for some reason. Would it be bad for it to then actually work in the new version? No, clearly not.

@somebody1234
Copy link

Would it be bad for it to then actually work in the new version? No, clearly not.

correct - it is not a breaking change, as there are not errors in a new version where there were none in a previous version.

@coolCucumber-cat
Copy link
Author

@somebody1234 I thought you might say that. In case you're not intentionally winding me up, no, it doesn't dissappear. Like you said, it's now bytecode. And guess what bytecode and JS can do? Things. Like if I tell JS or bytecode to make the screen be blue, it can do that.

Right now, write some TS code. Then compile it. What does it look like? Well, like this: "". Those are double quotes by the way, it looks like this: ''. Let me make it clearer by adding a comment: "// there is literally no code here. it can't do anything. if it breaks, nothing happens. worst case scenario, someone fixes a bug which actually maybe does affect something."

@somebody1234
Copy link

@coolCucumber-cat in that case what is the difference between TS -> JS -> bytecode and JS -> bytecode? regardless, it is not the JS that is doing anything.

console.log(1 + 1);

note that this is valid TS code.

@somebody1234
Copy link

a JS file containing "" would also do nothing, so i'm not quite sure what your point is.

@coolCucumber-cat
Copy link
Author

@somebody1234 Let me rephrase that. v1 works as intended. v2 allows you to write code that blows up your compter. v3 doesn't let you blow up your computer. So v3 is clearly good, even though it's a breaking change.

Wait, did you just imply that it would be fine if TS just allowed anything? Please say I'm misunderstanding you.

@somebody1234
Copy link

@coolCucumber-cat no, i said that it would not be a breaking change on the TS side.

@somebody1234
Copy link

addressing a few other points:

Does it somehow make things not work anymore?

only if noEmitOnError is set to true.

Will every website on the internet crash?

No, but plenty are written with TS, and it will be very difficult to work on them after upgrading their TS dependency.

Will the issue be really hard to fix?

Depends on the codebase size. Although, to be fair, this would be easy enough to "fix" with a codemod that adds as any to all JSON.parse (and the same for all other functions that return any).

@somebody1234
Copy link

it's not in TS itself, and so it's not ideal in that respect. but a huge fraction of projects already use eslint, so I don't think it's a particularly high barrier

@coolCucumber-cat
Copy link
Author

@somebody1234 Do I have to spell out everything for you? That's JS code in a TS file. "console.log(1 + 1)" is not TS code. It's JS code. And TS has nothing to do with that. TS cannot execute JS and JS cannot execute TS. other than enums or any old TS feature like that, write me some TS code (not JS), which actually does something. show me how to do "hello world" in TS. why should eslint be resposible for not doing the exact thing ts was supposed to do? "a huge fraction". yeah, not all. and i doubt most of them even have those features enabled. does that even fix the problem? it's not you using any, it's the standard library. if you could, what do you do? "as unknown"? that's hella confusing. especially in jsdoc and only typechecking. and this isn't even about dependencies, this is about the standard library. no dependencies here.

oh no, it works as expected and we eliminated bugs.

@coolCucumber-cat
Copy link
Author

Exetremely controversial opinion: bugs are bad and we should try to fix to them. if someone accidently writes bad code, we should try to prevent it. even if it breaks some code, that's a good thing because now people are aware of potential issues and can stop them. yeah, maybe it is a breaking change but @MartinJohns said "this aligns with the "Breaking Changes" section of the release notes", implying that updates sometimes include breaking changes. if breaking changes are so bad, why are we including it? that would make TS be even more hypocritical than saying any is bad and then using any everywhere. and the breaking change eliminates bugs too, so combined with the fact that they're allowed, it sure sounds like we should fix it.

@kalkronline
Copy link

it'd be strange if JSON.parse("1") gave a number type since that would only happen in cases where the string (the value) is predefined.

JSON.parse should probably return unknown or some JSON type, i'm sure there are many TS projects that don't use it properly and end up accidentally introducing unsoundness. But TS should only make this change if they have a mechanism to do it in a way that would be backwards compatible. (probably over 90% of projects use this and would break)

This is what I do to avoid the issues with JSON.parse bein any:

type JSONValue = string | number | boolean | null | JSONObject | JSONArray;
type JSONObject = { [x in string]?: JSONValue }
type JSONArray = Array<JSONValue>

/** Type safe version of JSON.parse */
export const parse: (...args: Parameters<typeof JSON.parse>) => JSONValue = JSON.parse;

/** Use when building a type narrowing function. */
type FromJSON<T> 
    = T extends JSONValue           ? T
    : T extends Record<string, any> ? {[K in keyof T]: FromJSON<T[K]>} & JSONObject 
    : T extends (infer U)[]         ? FromJSON<U>[]
    : T

// an example interface
interface Person {
    Name: string
    Age: number
}

// an example narrower
export function is_del_mesg(j: JSONValue): j is FromJSON<Person> {
    if (typeof j != "object" || j == null) return false; 
    if (!("Name" in j)) return false;
    if (typeof j.Name != "string") return false 
    if (!("Age" in j)) return false;
    if (typeof j.Age != "number") return false 
    
    return true;
}

@microsoft microsoft locked as too heated and limited conversation to collaborators Nov 30, 2023
@RyanCavanaugh
Copy link
Member

Insulting other users is a code of conduct violation that will quickly earn you an org block, especially if your response to a CoC reminder is further insults.

@RyanCavanaugh RyanCavanaugh closed this as not planned Won't fix, can't repro, duplicate, stale Nov 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants