-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
User libraries should be strict by default if written in TypeScript #3324
Comments
The TypeScript core team suggests that any new TypeScript project be enabled with Since TypeScript code in strict mode degrades well to sloppy mode, people can author for strict and still have it work in sloppy. We support a custom |
I am strongly 👍 here, because I would love Deno to be the first runtime that is not suffering from The Billion Dollar Mistake, and without the strict flags we still get runtime errors like those, without any hint from the compiler that something can be wrong with the code: Now is the only time when we can safely enable all strict flags by default. If we disable those flags now (which are not enabled by default by the TypeScript compiler itself only because of backwards compatibility but they are highly recommended by everyone) then after any significant amount of code for Deno is written and we need to maintain backwards compatibility, this decision will not be able to be changed later. Let's not make it one of the 10 things we regret about Deno few years from now. Without flags like const f = (x: string) => x.toLowerCase(); // OK for compiler, unsafe on run time doesn't guarantee that If, on the other hand, TypeScript has all strict flags enabled, I still can have a function that takes null or undefined if I want but I have to be explicit about it, and I will get a compiler error when I try to invoke const f = (x: string | null) => x.toLowerCase(); // COMPILE TIME ERROR
const f = (x: string | null) => x && x.toLowerCase(); // OK for compiler, safe on runtime (instead of I believe it is a false sense of safety to use TypeScript without strict null checks, I even gave a talk titled: Call me irresponsible if I ever crash on null or undefined in JavaScript or TypeScript exactly about this very topic. See also my comment in issue #504 here for some more details. I am 👍 for all strict flags enabled in Deno for all TypeScript code. |
FWIW I'm not a fan of forcing strict mode. It often means spending more time writing types with little gain. The compiler is rather good at inferring. StrictNullChecks should be on though. Also if a library author doesn't use strict mode but you do, it won't work out. |
Thanks to @maxmellen for this work. Let's see how annoying this is in practice... I am open to making strict mode non-default again if it turns out to be too verbose. |
I would expect it to be annoying when migrating, because strict mode will find a lot of subtle bugs (and With all new projects it should be easy since |
That's just asking for trouble. If one of your deps is not strict, your whole project cannot be. |
Per-module permissions/config/etc. are a rabbit hole I don't think we really want to go down. Non-strict code does no one any favours. If people can't get the upstream code to be strict, using |
Whole purpose of this issues is to force TypeScript to be strict, it's the default. It will be painful with user code that is non-strict. Problem is that there is now bunch of shoddily built TS deno code out there, it will be painful at the beginning, but strictness is default for TypeScript. |
True, and this should (hopefully) be a temporary problem anyway. It is still a bit weird to explicitly turn of strictness in my entire project, because a library (I trust) has forgotten a type annotation for a function that may not even be exported to the module. |
+1 for strictness. If you use a non-strict lib, perhaps consider making a PR to improve that lib to make it strict. |
I think it's worth mentioning that DefinitelyTyped's stance on this issue is that they consider that all the packages hosted in their repo should have Here's the default {
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"mypackage-tests.ts"
]
} |
That doesn't really translate though as DefinitelyTyped is types for exported public functions. And it is for code that is not strict (JavaScript). Those rules don't mean all normal TypeScript code should be noImplicitAny especially for internal implementations. |
@brandonkal You have a point there, although my comment was more of a reaction to @gewoonwoutje's comment. What I wanted to stress is that it seems the TypeScript ecosystem is moving in the direction of users being able to expect that libraries expose strictly typed interfaces which can be used in strict as well as non-strict codebases rather than users having to deal with libraries possibly having non-strict types and figuring out how to use such libraries in strict codebases. I'm also not aware of any TypeScript or Deno feature that lets a user specify which files should be considered part of a codebase's public API and which should be considered internal to that codebase, especially considering Deno does not require the use of any project configuration file. I would argue that defaulting to strict makes new code more interoperable with the rest of the ecosystem by default. |
Recently I found many third-party library massively broken by that changes. I think The best advantage of TypeScript is that users can select suitable typing power for their project. Indeed we provide custom I'm OK to enable strict mode for deno's internal code (cli/std) as it is the stand-alone project and should be fully-maintained. Again, "strict" is too opinionated for general purpose TypeScript runtime. Deno shouldn't force user to use specified compiler options. IMO: At least |
Being overly strict is painful for a scripting language. I would be using a scripting language to get things done quickly. If I wanted to be super-specific about what I was doing, I could just write it in Rust. This is unrelated to strict mode - but just a general comment about overly pedantic rules: in the Deno code base we have a lint rule which requires writing the return types. So for many async functions we end up writing Deno should be like a toy. Easy and simple to use. I acknowledge that there are going to be situations where people want to change tsconfig - but we should strive to make that the minority case. Most people should be able to start script with one file, most projects should not have to ever think about configuration. |
@ry if we reverse this, and I can understand the motivation, using strict should be fictionless as well... an easy step to upgrade your experience... If we introduced a Also, I would recommend we would continue to run |
@ry Why not disable that lint rule and allow TS to infer those? TS inference is really good, I have never ever needed to provide the return type of a function like that and I use TS strict mode always. It seems like that lint rule is causing more harm than helping.
100% agree. But every toy has certain standards, for example choking hazards for kids. If I go to a toy store, I expect the toys there to meet a certain standard. It would be nice to have the ability to say that all Deno libs meet the TS strict standard. |
The fact that TypeScript is defaulting to strict mode, is a strong suggestion that we should as well. The incompatibilities that @keroxp is experiencing will go away as people update code to work with latest versions of deno - it can be chalked up to unfortunate growing pains. We'll leave strict mode on by default for now - in particular @piscisaureus and @bartlomieju both are in favor of it. (And certainly we will always maintain very strict linting rules for Deno's internal code) I worry about the user who has prototyped something quickly in JS, and now wants to start slowly adding types - but finds that when they rename their .js to .ts they suddenly have to update every function definition. It seems like a major benefit of typescript is lost if it's "all or nothing". |
As I mentioned above, |
No need to worry, they have config. The temporary transition phase should of course be the one that requires config. That way the config is temporary. |
Do you honestly expect someone to write a config file to prototype something? That's an unfair justification @nayeemrmn and just a bad user experience. Config is rarely ever temporary. |
@brandonkal Umm, no... the prototyper is using JS. We're talking about the person progressing from that, aren't we? :) Also I'm in favour of a flag.
What does that mean here? I'm saying that strict is the one you're hardly going to go back from, non-strict might be temporary so it should be the specified one. |
This was @kitsonk 's suggestion of Potentially there could be a message on strictness errors suggesting this flag. |
I agree with @nayeemrmn logic here. When you are gradually adding types (converting between JS and TS) you can just add When you are done you can just remove |
I agree with @ry and @brandonkal. And the real problem is that there are no way to apply configuration for each remote modules that depend on. There are incompatibility between strict code and "sloppy" code (for each other. Some valid code in strict may be invalid in non-strict mode). Custom IMO: If it were really the ideal and correct way of programming, its name won't be "strict". |
Really? What is that code you write in strict mode which is not usable in non-strict mode? However the reverse is true: non-strict code is not usable in strict mode. This is the reason DT defaults to having more flags turned on. If the deno defaults to non-strict mode the libraries start to gather non-strict code and you can never use those libraries with strict mode. |
Summary is here: export type BulkResult = string | undefined;
export type RedisRawReply =
| ["status", string]
| ["integer", number]
| ["bulk", BulkResult]
| ["array", any[]]
| ["error", Error];
function rawReply(): RedisRawReply {
return ["bulk", "result"]
}
function getBulkResult(val: string | number | undefined): BulkResult {
const [_, reply] = rawReply();
if (typeof reply !== "string" && reply != null) {
throw new Error();
}
return reply;
} With
I don't what happened clearly. It seems that |
@keroxp that has nothing to do with noImplicitAny, I pasted your code here: And tune "noImplicitAny" on or off, it won't give errors in either mode. No errors in strict or otherwise. None in this thread is actually anymore advocating for completly non-strict code btw, we are talking about noImplicitAny here mostly. |
It is, according to the TypeScript core team, it is the correct way of programming. I've talked to them personally. Just like It is true that some strict code will break in sloppy mode. The specific example given |
I don't get why people allow TypeScript to prevent them from running code. You're not forced to listen to the TypeScript errors. You can always run your code using Deno's TypeScript should be seen like a linter. They're helpful hints during development, but they don't prevent you from running the code at all at any time. This is also why I'd vote for strict type checking, including |
We have been run with |
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
Fixes denoland/deno#3324 Co-authored-by: Kitson Kelly <me@kitsonkelly.com>
My opinion is that:
.ts
files should be as strict as possible (you can do anything withas any
trickery still).js
files should be free to do what ever you want.Also I think there is no audience who loves working with non-strict TypeScript, it's mainly used by people who are migrating to TypeScript. Catering to "non-strict" TypeScript people is failure in waiting.
(Going in the reverse is more painful, because the libraries will then not type check, if we allow non-strict scripts to prevail.)
Point being that if you use TS you probably love the types and the strictness, if you don't you use JS anyway.
Opening this on suggestion by @kitsonk in #504
The text was updated successfully, but these errors were encountered: