Skip to content

Enable --strict by default #62333

@DanielRosenwasser

Description

@DanielRosenwasser

Background

Almost a decade ago, we began to add certain options beyond --noImplicitAny and --strictNullChecks. Flags like --strictFunctionTypes, --noImplicitThis, and --strictBindCallApply have been added to ensure most code is hardened against certain classes of type safety bugs. To avoid thinking about all the specific type-checking flags we recommended, we added the --strict flag as an easy way to enable them all. Each flag in the "--strict family" was still off by default, and so was --strict itself; but all of them would be conveniently enabled when turning on --strict. In cases where users found the behaviors of individual flags to be frustrating, or a new setting added under --strict broke their code, it has always been possible to toggle those individual settings to their false state even while --strict is set to true.

These settings were added as opt-ins so that our developers could avoid breaks, and migrations to TypeScript could be as easy as possible. But for years now, we've framed most of --strict as a collection of decisions we would have made in TypeScript if we had the chance to start things all over again. We still want to carry our community forward, but we want new TypeScript code to get the best experience out of the box.

While lots of code relies on laxer strictness settings, we have recommended that --strict be enabled for many years. tsc --init has set "strict": true for the better part of a decade. We are seeing that more and more developers pick TypeScript for JavaScript development, and expect stricter type-checking by default. For most new projects, --strict being off feels like it's usually an accident, and a pit-of-failure experience that we want users to avoid.

In TypeScript 6.0 and 7.0, we want to go a step further than explicitly setting --strict in tsc --init: by enabling it by default.

Proposal

TypeScript 6.0 will assume that --strict is on, unless explicitly disabled.
This means that specific settings like --strictNullChecks and --noImplicitAny will be enabled automatically unless --strict is explicitly turned off.

Projects that encounter breaks from this change will be able to do one of the following:

  • adjust code to be compatible with all strict behaviors
  • turn specific strictness flags off
  • turn --strict off explicitly

Developers can consider partial migrations over time through a combination of the above.

Open Questions

What should tsc --init generate?

If TypeScript 5.9 and earlier still assume that --strict is false, should tsc --init should still continue explicitly setting "strict": true in generated tsconfig.json files? Is it worth keeping in there for awareness, or do we want to free users of ever thinking of --strict again?

While I personally felt that it would be worth keeping strict in there for broader compatibility with older TypeScript versions, I wonder how much of a win this really is. Over time, all developers will experience a new built-in TypeScript in their editors, or will be expected to use a the version of TypeScript that was run with tsc --init.

I don't think it hurts that much to leave things as-is for now, but I'm open to us changing it.

What should the default experience be in editors for loose files?

Today, editors like VS Code are able to specify the settings for loose files. By "loose files", we mean files where a tsconfig.json couldn't be found, or untitled TypeScript/JavaScript buffers. In these cases, we create what's called an "inferred project".

When a loose file is opened with our language service, we apply a default set of settings. For TypeScript, we try to adopt some loose runtime rules (e.g. high ECMAScript --targets, lax module resolution, etc.). This makes it slightly easier to have files can be built and run without a tsconfig.json or jsconfig.json.

While this is fairly rare for TypeScript files...

  • it is definitely already common to see JavaScript files with no tsconfig.json or jsconfig.json, and
  • it may become more common to run loose TypeScript "scripts" now that Node.js, Deno, and Bun all support running TypeScript directly.

For JavaScript, this matters more in cases where // @ts-check (or similar ways of checking JavaScript files in the editor) are used. Either way, noImplicitAny can be a bit rough when using untyped libraries. Maybe we should perform automatic type acquisition for loose TypeScript files, but it would be confusing to lose typing when a user creates their first tsconfig.json.

We could effectively punt on answering "what should the new behavior be?" by explicitly having editors turn --strict mode off for inferred projects. This would maintain the status quo today. We would either:

  • modify editors using TSServer to explicitly opt in here
  • set strict: false as the default setting of inferred projects

I do think we may want to experiment with --strict on by default in inferred projects before making a call here.

More Information

More information on 6.0 breaking changes and deprecations is available at #54500.

Metadata

Metadata

Labels

Breaking ChangeWould introduce errors in existing codeCommittedThe team has roadmapped this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions