Was this page helpful?

Variable Declaration

let and const are two relatively new concepts for variable declarations in JavaScript. As we mentioned earlier , let is similar to var in some respects, but allows users to avoid some of the common “gotchas” that users run into in JavaScript.

const is an augmentation of let in that it prevents re-assignment to a variable.

With TypeScript being an extension of JavaScript, the language naturally supports let and const . Here we’ll elaborate more on these new declarations and why they’re preferable to var .

If you’ve used JavaScript offhandedly, the next section might be a good way to refresh your memory. If you’re intimately familiar with all the quirks of var declarations in JavaScript, you might find it easier to skip ahead.

var declarations

Declaring a variable in JavaScript has always traditionally been done with the var keyword.

As you might’ve figured out, we just declared a variable named a with the value 10 .

We can also declare a variable inside of a function:

and we can also access those same variables within other functions:

In this above example, g captured the variable a declared in f . At any point that g gets called, the value of a will be tied to the value of a in f . Even if g is called once f is done running, it will be able to access and modify a .

Scoping rules

var declarations have some odd scoping rules for those used to other languages. Take the following example:

Some readers might do a double-take at this example. The variable x was declared within the if block , and yet we were able to access it from outside that block. That’s because var declarations are accessible anywhere within their containing function, module, namespace, or global scope - all which we’ll go over later on - regardless of the containing block. Some people call this var -scoping or function-scoping . Parameters are also function scoped.

These scoping rules can cause several types of mistakes. One problem they exacerbate is the fact that it is not an error to declare the same variable multiple times:

Maybe it was easy to spot out for some experienced JavaScript developers, but the inner for -loop will accidentally overwrite the variable i because i refers to the same function-scoped variable. As experienced developers know by now, similar sorts of bugs slip through code reviews and can be an endless source of frustration.

Variable capturing quirks

Take a quick second to guess what the output of the following snippet is:

For those unfamiliar, setTimeout will try to execute a function after a certain number of milliseconds (though waiting for anything else to stop running).

Ready? Take a look:

Many JavaScript developers are intimately familiar with this behavior, but if you’re surprised, you’re certainly not alone. Most people expect the output to be

Remember what we mentioned earlier about variable capturing? Every function expression we pass to setTimeout actually refers to the same i from the same scope.

Let’s take a minute to consider what that means. setTimeout will run a function after some number of milliseconds, but only after the for loop has stopped executing; By the time the for loop has stopped executing, the value of i is 10 . So each time the given function gets called, it will print out 10 !

A common work around is to use an IIFE - an Immediately Invoked Function Expression - to capture i at each iteration:

This odd-looking pattern is actually pretty common. The i in the parameter list actually shadows the i declared in the for loop, but since we named them the same, we didn’t have to modify the loop body too much.

let declarations

By now you’ve figured out that var has some problems, which is precisely why let statements were introduced. Apart from the keyword used, let statements are written the same way var statements are.

The key difference is not in the syntax, but in the semantics, which we’ll now dive into.


When a variable is declared using let , it uses what some call lexical-scoping or block-scoping . Unlike variables declared with var whose scopes leak out to their containing function, block-scoped variables are not visible outside of their nearest containing block or for -loop.

Here, we have two local variables a and b . a ’s scope is limited to the body of f while b ’s scope is limited to the containing if statement’s block.

Variables declared in a catch clause also have similar scoping rules.

Another property of block-scoped variables is that they can’t be read or written to before they’re actually declared. While these variables are “present” throughout their scope, all points up until their declaration are part of their temporal dead zone . This is just a sophisticated way of saying you can’t access them before the let statement, and luckily TypeScript will let you know that.

Something to note is that you can still capture a block-scoped variable before it’s declared. The only catch is that it’s illegal to call that function before the declaration. If targeting ES2015, a modern runtime will throw an error; however, right now TypeScript is permissive and won’t report this as an error.

For more information on temporal dead zones, see relevant content on the Mozilla Developer Network .

Re-declarations and Shadowing

With var declarations, we mentioned that it didn’t matter how many times you declared your variables; you just got one.

In the above example, all declarations of x actually refer to the same x , and this is perfectly valid. This often ends up being a source of bugs. Thankfully, let declarations are not as forgiving.

The variables don’t necessarily need to both be block-scoped for TypeScript to tell us that there’s a problem.

That’s not to say that a block-scoped variable can never be declared with a function-scoped variable. The block-scoped variable just needs to be declared within a distinctly different block.

The act of introducing a new name in a more nested scope is called shadowing . It is a bit of a double-edged sword in that it can introduce certain bugs on its own in the event of accidental shadowing, while also preventing certain bugs. For instance, imagine we had written our earlier sumMatrix function using let variables.

This version of the loop will actually perform the summation correctly because the inner loop’s i shadows i from the outer loop.

Shadowing should usually be avoided in the interest of writing clearer code. While there are some scenarios where it may be fitting to take advantage of it, you should use your best judgement.

Block-scoped variable capturing

When we first touched on the idea of variable capturing with var declaration, we briefly went into how variables act once captured. To give a better intuition of this, each time a scope is run, it creates an “environment” of variables. That environment and its captured variables can exist even after everything within its scope has finished executing.

Because we’ve captured city from within its environment, we’re still able to access it despite the fact that the if block finished executing.

Recall that with our earlier setTimeout example, we ended up needing to use an IIFE to capture the state of a variable for every iteration of the for loop. In effect, what we were doing was creating a new variable environment for our captured variables. That was a bit of a pain, but luckily, you’ll never have to do that again in TypeScript.

let declarations have drastically different behavior when declared as part of a loop. Rather than just introducing a new environment to the loop itself, these declarations sort of create a new scope per iteration . Since this is what we were doing anyway with our IIFE, we can change our old setTimeout example to just use a let declaration.

and as expected, this will print out

const declarations

const declarations are another way of declaring variables.

They are like let declarations but, as their name implies, their value cannot be changed once they are bound. In other words, they have the same scoping rules as let , but you can’t re-assign to them.

This should not be confused with the idea that the values they refer to are immutable .

Unless you take specific measures to avoid it, the internal state of a const variable is still modifiable. Fortunately, TypeScript allows you to specify that members of an object are readonly . The chapter on Interfaces has the details.

let vs. const

Given that we have two types of declarations with similar scoping semantics, it’s natural to find ourselves asking which one to use. Like most broad questions, the answer is: it depends.

Applying the principle of least privilege , all declarations other than those you plan to modify should use const . The rationale is that if a variable didn’t need to get written to, others working on the same codebase shouldn’t automatically be able to write to the object, and will need to consider whether they really need to reassign to the variable. Using const also makes code more predictable when reasoning about flow of data.

Use your best judgement, and if applicable, consult the matter with the rest of your team.

The majority of this handbook uses let declarations.


Another ECMAScript 2015 feature that TypeScript has is destructuring. For a complete reference, see the article on the Mozilla Developer Network . In this section, we’ll give a short overview.

Array destructuring

The simplest form of destructuring is array destructuring assignment:

This creates two new variables named first and second . This is equivalent to using indexing, but is much more convenient:

Destructuring works with already-declared variables as well:

And with parameters to a function:

You can create a variable for the remaining items in a list using the syntax ... :

Of course, since this is JavaScript, you can just ignore trailing elements you don’t care about:

Or other elements:

Tuple destructuring

Tuples may be destructured like arrays; the destructuring variables get the types of the corresponding tuple elements:

It’s an error to destructure a tuple beyond the range of its elements:

As with arrays, you can destructure the rest of the tuple with ... , to get a shorter tuple:

Or ignore trailing elements, or other elements:

Object destructuring

You can also destructure objects:

This creates new variables a and b from o.a and o.b . Notice that you can skip c if you don’t need it.

Like array destructuring, you can have assignment without declaration:

Notice that we had to surround this statement with parentheses. JavaScript normally parses a { as the start of block.

You can create a variable for the remaining items in an object using the syntax ... :

Property renaming

You can also give different names to properties:

Here the syntax starts to get confusing. You can read a: newName1 as ” a as newName1 ”. The direction is left-to-right, as if you had written:

Confusingly, the colon here does not indicate the type. The type, if you specify it, still needs to be written after the entire destructuring:

Default values

Default values let you specify a default value in case a property is undefined:

In this example the b? indicates that b is optional, so it may be undefined . keepWholeObject now has a variable for wholeObject as well as the properties a and b , even if b is undefined.

Function declarations

Destructuring also works in function declarations. For simple cases this is straightforward:

But specifying defaults is more common for parameters, and getting defaults right with destructuring can be tricky. First of all, you need to remember to put the pattern before the default value.

The snippet above is an example of type inference, explained earlier in the handbook.

Then, you need to remember to give a default for optional properties on the destructured property instead of the main initializer. Remember that C was defined with b optional:

Use destructuring with care. As the previous example demonstrates, anything but the simplest destructuring expression is confusing. This is especially true with deeply nested destructuring, which gets really hard to understand even without piling on renaming, default values, and type annotations. Try to keep destructuring expressions small and simple. You can always write the assignments that destructuring would generate yourself.

The spread operator is the opposite of destructuring. It allows you to spread an array into another array, or an object into another object. For example:

This gives bothPlus the value [0, 1, 2, 3, 4, 5] . Spreading creates a shallow copy of first and second . They are not changed by the spread.

You can also spread objects:

Now search is { food: "rich", price: "$$", ambiance: "noisy" } . Object spreading is more complex than array spreading. Like array spreading, it proceeds from left-to-right, but the result is still an object. This means that properties that come later in the spread object overwrite properties that come earlier. So if we modify the previous example to spread at the end:

Then the food property in defaults overwrites food: "rich" , which is not what we want in this case.

Object spread also has a couple of other surprising limits. First, it only includes an objects’ own, enumerable properties . Basically, that means you lose methods when you spread instances of an object:

Second, the TypeScript compiler doesn’t allow spreads of type parameters from generic functions. That feature is expected in future versions of the language.

The TypeScript docs are an open source project. Help us improve these pages by sending a Pull Request ❤

Daniel Rosenwasser  (58)

Last updated: Mar 01, 2023  

assignment operators typescript

Announcing TypeScript 4.0

' data-src=

Daniel Rosenwasser

August 20th, 2020 2 0

Today we are thrilled to announce the availability of TypeScript 4.0! This version of the language represents our next generation of TypeScript releases, as we dive deeper into expressivity, productivity, and scalability.

If you’re not familiar with TypeScript, it’s a language that builds on top of JavaScript by adding syntax for static types . The idea is that by writing down the types of your values and where they’re used, you can use TypeScript to type-check your code and tell you about mistakes before you run your code (and even before saving your file). You can then use the TypeScript compiler to then strip away types from your code, and leaving you with clean, readable JavaScript that runs anywhere. Beyond checking, TypeScript also uses static types to power great editor tooling like auto-completion, code navigation, refactorings, and more. In fact, if you’ve used JavaScript in an editor like Visual Studio Code or Visual Studio, you’ve already been using an experience powered by types and TypeScript. You can learn more about all of this on our website .

With TypeScript 4.0, there are no major breaking changes. In fact, if you’re new to the language, now is the best time to start using it. The community is already here and growing, with working code and great new resources to learn. And one thing to keep in mind: despite all the good stuff we’re bringing in 4.0, you really only need to know the basics of TypeScript to be productive!

If you’re already using TypeScript in your project, you can either get it through NuGet or use npm with the following command:

You can also get editor support by

The 4.0 Journey

TypeScript is a core part of many people’s JavaScript stack today. On npm, TypeScript saw over 50 million monthly downloads for the first time in July! And while we recognize there’s always room for growth and improvement, it’s clear that most people coding in TypeScript really do enjoy it. StackOverflow’s most recent developer survey pins TypeScript as the 2nd most-loved language . In the most recent State of JS Survey, around 89% of developers who used TypeScript said that they would use it again .

It’s worth digging a bit into how we got here. In our past two major versions, we looked back at some highlights that shined over the years. For TypeScript 4.0, we’re going to keep up that tradition.

Looking back from 3.0 onward, there’s a dizzying number of changes, but TypeScript 3.0 itself came out with a punch. Unifying tuple types and parameter lists was a big highlight, enabling tons of existing JavaScript patterns on functions. The release also featured project references to help scale up, organize, and share across codebases. One small change that had a big impact was that 3.0 introduced a type-safe alternative to any called unknown .

TypeScript 3.1 extended the capabilities of mapped types to work on tuple and array types, and made it dramatically easier to attach properties to functions without resorting to TypeScript-specific runtime features that have fallen out of use.

TypeScript 3.2 allowed object spreads on generic types, and leveraged 3.0’s capabilities to better model meta-programming with functions by strictly typing bind , call , and apply . TypeScript 3.3 focused a bit on stability following 3.2, but also brought quality-of-life improvements when using union type methods, and added file-incremental builds under --build mode.

In the 3.4 release , we leaned farther into supporting functional patterns, with better support for immutable data structures, and improved inference on higher-order generic functions. As a big plus, this release introduced the --incremental flag, a way to get faster compiles and type-checks by avoiding a full rebuild on every run of TypeScript, without project references.

With TypeScript 3.5 and 3.6 , we saw some tightening up of the type system rules, along with smarter compatibility checking rules.

TypeScript 3.7 was a very noteworthy release because it featured a rich combination of new type system features with ECMAScript features. From the type-system side, we saw recursive type alias references and support for assertion-style functions, both which are unique type-system features. From the JavaScript side, the release brought optional chaining and coalescing, two of the most highly demanded features for TypeScript and JavaScript users alike, championed in TC39 in part by our team.

Much more recently, 3.8 and 3.9 have brought type-only imports/exports, along with ECMAScript features like private fields, top-level await in modules, and new export * syntaxes. These releases also delivered performance and scalability optimizations.

We haven’t even touched on all the work in our language service, our infrastructure, our website, and other core projects which are incredibly valuable to the TypeScript experience. Beyond the core team’s projects is the incredible community of contributors in the ecosystem, pushing the experience forward, and helping out with DefinitelyTyped and even TypeScript itself. DefinitelyTyped had just 80 pull requests in 2012 when it first started, picking up on the tail end of the year. In 2019, it had over 8300 pull requests , which still astounds us. These contributions are fundamental to the TypeScript experience, so we’re grateful for such a bustling and eager community that’s been improving the ecosystem and pushed us to constantly improve.

What’s New?

All this brings us to 4.0! So, without further ado, let’s dive into what’s new!

Variadic Tuple Types

Labeled tuple elements, class property inference from constructors, short-circuiting assignment operators.

Custom JSX Factories

Speed improvements in build mode with --noemitonerror, --incremental with --noemit, convert to optional chaining, /** @deprecated */ support, partial semantic mode at startup, smarter auto-imports, our new website, breaking changes.

Consider a function in JavaScript called concat that takes two array or tuple types and concatenates them together to make a new array.

Also consider tail , that takes an array or tuple, and returns all elements but the first.

How would we type either of these in TypeScript?

For concat , the only valid thing we could do in older versions of the language was to try and write some overloads.

Uh…okay, that’s…seven overloads for when the second array is always empty. Let’s add some for when arr2 has one argument.

We hope it’s clear that this is getting unreasonable. Unfortunately, you’d also end up with the same sorts of issues typing a function like tail .

This is another case of what we like to call “death by a thousand overloads”, and it doesn’t even solve the problem generally. It only gives correct types for as many overloads as we care to write. If we wanted to make a catch-all case, we’d need an overload like the following:

But that signature doesn’t encode anything about the lengths of the input, or the order of the elements, when using tuples.

TypeScript 4.0 brings two fundamental changes, along with inference improvements, to make typing these possible.

The first change is that spreads in tuple type syntax can now be generic. This means that we can represent higher-order operations on tuples and arrays even when we don’t know the actual types we’re operating over. When generic spreads are instantiated (or, replaced with a real type) in these tuple types, they can produce other sets of array and tuple types.

For example, that means we can type function like tail , without our “death by a thousand overloads” issue.

The second change is that rest elements can occur anywhere in a tuple – not just at the end!

Previously, TypeScript would issue an error like the following:

But with TypeScript 4.0, this restriction is relaxed.

Note that in cases when we spread in a type without a known length, the resulting type becomes unbounded as well, and all the following elements factor into the resulting rest element type.

By combining both of these behaviors together, we can write a single well-typed signature for concat :

While that one signature is still a bit lengthy, it’s just one signature that doesn’t have to be repeated, and it gives predictable behavior on all arrays and tuples.

This functionality on its own is great, but it shines in more sophisticated scenarios too. For example, consider a function to partially apply arguments called partialCall . partialCall takes a function – let’s call it f – along with the initial few arguments that f expects. It then returns a new function that takes any other arguments that f still needs, and calls f when it receives them.

TypeScript 4.0 improves the inference process for rest parameters and rest tuple elements so that we can type this and have it “just work”.

In this case, partialCall understands which parameters it can and can’t initially take, and returns functions that appropriately accept and reject anything left over.

Variadic tuple types enable a lot of new exciting patterns, especially around function composition. We expect we may be able to leverage it to do a better job type-checking JavaScript’s built-in bind method. A handful of other inference improvements and patterns also went into this, and if you’re interested in learning more, you can take a look at the pull request for variadic tuples.

Improving the experience around tuple types and parameter lists is important because it allows us to get strongly typed validation around common JavaScript idioms – really just slicing and dicing argument lists and passing them to other functions. The idea that we can use tuple types for rest parameters is one place where this is crucial.

For example, the following function that uses a tuple type as a rest parameter…

…should appear no different from the following function…

…for any caller of foo .

There is one place where the differences begin to become observable though: readability. In the first example, we have no parameter names for the first and second elements. While these have no impact on type-checking, the lack of labels on tuple positions can make them harder to use – harder to communicate our intent.

That’s why in TypeScript 4.0, tuples types can now provide labels.

To deepen the connection between parameter lists and tuple types, the syntax for rest elements and optional elements mirrors the syntax for parameter lists.

There are a few rules when using labeled tuples. For one, when labeling a tuple element, all other elements in the tuple must also be labeled.

It’s worth noting – labels don’t require us to name our variables differently when destructuring. They’re purely there for documentation and tooling.

Overall, labeled tuples are handy when taking advantage of patterns around tuples and argument lists, along with implementing overloads in a type-safe way. In fact, TypeScript’s editor support will try to display them as overloads when possible.

To learn more, check out the pull request for labeled tuple elements.

TypeScript 4.0 can now use control flow analysis to determine the types of properties in classes when noImplicitAny is enabled.

In cases where not all paths of a constructor assign to an instance member, the property is considered to potentially be undefined .

In cases where you know better (e.g. you have an initialize method of some sort), you’ll still need an explicit type annotation along with a definite assignment assertion ( ! ) if you’re in strictPropertyInitialization .

For more details, see the implementing pull request .

JavaScript, and a lot of other languages, support a set of operators called compound assignment operators. Compound assignment operators apply an operator to two arguments, and then assign the result to the left side. You may have seen these before:

So many operators in JavaScript have a corresponding assignment operator! Up until recently, however, there were three notable exceptions: logical and ( && ), logical or ( || ), and nullish coalescing ( ?? ).

That’s why TypeScript 4.0 supports a new ECMAScript feature to add three new assignment operators: &&= , ||= , and ??= .

These operators are great for substituting any example where a user might write code like the following:

Or a similar if block like

There are even some patterns we’ve seen (or, uh, written ourselves) to lazily initialize values, only if they’ll be needed.

(look, we’re not proud of all the code we write…)

On the rare case that you use getters or setters with side-effects, it’s worth noting that these operators only perform assignments if necessary. In that sense, not only is the right side of the operator “short-circuited” – the assignment itself is too.

Try running the following example to see how that differs from always performing the assignment.

We’d like to extend a big thanks to community member Wenlu Wang for this contribution!

For more details, you can take a look at the pull request here . You can also check out TC39’s proposal repository for this feature .

unknown on catch Clause Bindings

Since the beginning days of TypeScript, catch clause variables have always been typed as any . This meant that TypeScript allowed you to do anything you wanted with them.

The above has some undesirable behavior if we’re trying to prevent more errors from happening in our error-handling code! Because these variables have the type any by default, they lack any type-safety which could have errored on invalid operations.

That’s why TypeScript 4.0 now lets you specify the type of catch clause variables as unknown instead. unknown is safer than any because it reminds us that we need to perform some sorts of type-checks before operating on our values.

While the types of catch variables won’t change by default, we might consider a new --strict mode flag in the future so that users can opt in to this behavior. In the meantime, it should be possible to write a lint rule to force catch variables to have an explicit annotation of either : any or : unknown .

For more details you can peek at the changes for this feature .

When using JSX, a fragment is a type of JSX element that allows us to return multiple child elements. When we first implemented fragments in TypeScript, we didn’t have a great idea about how other libraries would utilize them. Nowadays most other libraries that encourage using JSX and support fragments have a similar API shape.

In TypeScript 4.0, users can customize the fragment factory through the new jsxFragmentFactory option.

As an example, the following tsconfig.json file tells TypeScript to transform JSX in a way compatible with React, but switches each factory invocation to h instead of React.createElement , and uses Fragment instead of React.Fragment .

In cases where you need to have a different JSX factory on a per-file basis, you can take advantage of the new /** @jsxFrag */ pragma comment. For example, the following…

…will get transformed to this output JavaScript…

We’d like to extend a big thanks to community member Noj Vek for sending this pull request and patiently working with our team on it.

You can see that the pull request for more details!

Previously, compiling a program after a previous compile with errors under --incremental would be extremely slow when using the --noEmitOnError flag. This is because none of the information from the last compilation would be cached in a .tsbuildinfo file based on the --noEmitOnError flag.

TypeScript 4.0 changes this which gives a great speed boost in these scenarios, and in turn improves --build mode scenarios (which imply both --incremental and --noEmitOnError ).

For details, read up more on the pull request .

TypeScript 4.0 allows us to use the --noEmit flag when while still leveraging --incremental compiles. This was previously not allowed, as --incremental needs to emit a .tsbuildinfo files; however, the use-case to enable faster incremental builds is important enough to enable for all users.

For more details, you can see the implementing pull request .

Editor Improvements

The TypeScript compiler doesn’t only power the editing experience for TypeScript itself in most major editors – it also powers the JavaScript experience in the Visual Studio family of editors and more. For that reason, much of our work focuses on improving editor scenarios – the place you spend most of your time as a developer.

Using new TypeScript/JavaScript functionality in your editor will differ depending on your editor, but

You can check out a partial list of editors that have support for TypeScript to learn more about whether your favorite editor has support to use new versions.

Optional chaining is a recent feature that’s received a lot of love. That’s why TypeScript 4.0 brings a new refactoring to convert common patterns to take advantage of optional chaining and nullish coalescing !

Keep in mind that while this refactoring doesn’t perfectly capture the same behavior due to subtleties with truthiness/falsiness in JavaScript, we believe it should capture the intent for most use-cases, especially when TypeScript has more precise knowledge of your types.

For more details, check out the pull request for this feature .

TypeScript’s editing support now recognizes when a declaration has been marked with a /** @deprecated * JSDoc comment. That information is surfaced in completion lists and as a suggestion diagnostic that editors can handle specially. In an editor like VS Code, deprecated values are typically displayed a strike-though style like this .

Some examples of deprecated declarations with strikethrough text in the editor

This new functionality is available thanks to Wenlu Wang . See the pull request for more details.

We’ve heard a lot from users suffering from long startup times, especially on bigger projects. The culprit is usually a process called program construction . This is the process of starting with an initial set of root files, parsing them, finding their dependencies, parsing those dependencies, finding those dependencies’ dependencies, and so on. The bigger your project is, the longer you’ll have to wait before you can get basic editor operations like go-to-definition or quick info.

That’s why we’ve been working on a new mode for editors to provide a partial experience until the full language service experience has loaded up. The core idea is that editors can run a lightweight partial server that only looks at the current files that the editor has open.

It’s hard to say precisely what sorts of improvements you’ll see, but anecdotally, it used to take anywhere between 20 seconds to a minute before TypeScript would become fully responsive on the Visual Studio Code codebase. In contrast, our new partial semantic mode seems to bring that delay down to just a few seconds . As an example, in the following video, you can see two side-by-side editors with TypeScript 3.9 running on the left and TypeScript 4.0 running on the right.

When restarting both editors on a particularly large codebase, the one with TypeScript 3.9 can’t provide completions or quick info at all. On the other hand, the editor with TypeScript 4.0 can immediately give us a rich experience in the current file we’re editing, despite loading the full project in the background.

Currently the only editor that supports this mode is Visual Studio Code which has some UX improvements coming up in Visual Studio Code Insiders . We recognize that this experience may still have room for polish in UX and functionality, and we have a list of improvements in mind. We’re looking for more feedback on what you think might be useful.

For more information, you can see the original proposal , the implementing pull request , along with the follow-up meta issue .

Auto-import is a fantastic feature that makes coding a lot easier; however, every time auto-import doesn’t seem to work, it can throw users off a lot. One specific issue that we heard from users was that auto-imports didn’t work on dependencies that were written in TypeScript – that is, until they wrote at least one explicit import somewhere else in their project.

Why would auto-imports work for @types packages, but not for packages that ship their own types? It turns out that auto-imports only work on packages your project already includes. Because TypeScript has some quirky defaults that automatically add packages in node_modules/@types to your project, those packages would be auto-imported. On the other hand, other packages were excluded because crawling through all your node_modules packages can be really expensive.

All of this leads to a pretty lousy getting started experience for when you’re trying to auto-import something that you’ve just installed but haven’t used yet.

TypeScript 4.0 now does a little extra work in editor scenarios to include the packages you’ve listed in your package.json ‘s dependencies (and peerDependencies ) fields. The information from these packages is only used to improve auto-imports, and doesn’t change anything else like type-checking. This allows us to provide auto-imports for all of your dependencies that have types, without incurring the cost of a complete node_modules search.

In the rare cases when your package.json lists more than ten typed dependencies that haven’t been imported yet, this feature automatically disables itself to prevent slow project loading. To force the feature to work, or to disable it entirely, you should be able to configure your editor. For Visual Studio Code, this is the “Include Package JSON Auto Imports” (or typescript.preferences.includePackageJsonAutoImports ) setting.

Configuring 'include package JSON auto imports'

The TypeScript website has recently been rewritten from the ground up and rolled out!

A screenshot of the new TypeScript website

We already wrote a bit about our new site , so you can read up more there; but it’s worth mentioning that we’re still looking to hear what you think! If you have questions, comments, or suggestions, you can file them over on the website’s issue tracker .

lib.d.ts Changes

Our lib.d.ts declarations have changed – most specifically, types for the DOM have changed. The most notable change may be the removal of document.origin which only worked in old versions of IE and Safari MDN recommends moving to self.origin .

Properties Overriding Accessors (and vice versa) is an Error

Previously, it was only an error for properties to override accessors, or accessors to override properties, when using useDefineForClassFields ; however, TypeScript now always issues an error when declaring a property in a derived class that would override a getter or setter in the base class.

See more details on the implementing pull request .

Operands for delete must be optional.

When using the delete operator in strictNullChecks , the operand must now be any , unknown , never , or be optional (in that it contains undefined in the type). Otherwise, use of the delete operator is an error.

Usage of TypeScript’s Node Factory is Deprecated

Today TypeScript provides a set of “factory” functions for producing AST Nodes; however, TypeScript 4.0 provides a new node factory API. As a result, for TypeScript 4.0 we’ve made the decision to deprecate these older functions in favor of the new ones.

For more details, read up on the relevant pull request for this change .

What’s Next?

You’ve reached the end of this release post, but luckily there’s more coming. TypeScript 4.1’s iteration plan is already up so you can get a sense of what’s on the horizon. In the meantime, you can give new features in 4.1 a shot by using nightly builds in your workspace , or maybe just in your editor . Whether you’re on TypeScript 4.0, or the next version, we’re interested in hearing feedback! Feel free to leave a comment below, reach out over Twitter , or file an issue on GitHub .

We said it once, and we’ll say it again: we owe so much to our community for all their work and dedication. In turn, we want to making coding in TypeScript and JavaScript the pure joy you deserve. This involves not just focusing on one thing, but a combination of improving the language and editing experience, keeping an eye on speed, iterating on our UX, smoothing the onboarding and learning experience as a whole, and more.

Thank you so much, and enjoy 4.0!

Happy Hacking!

– Daniel Rosenwasser and the TypeScript Team

' data-src=

Daniel Rosenwasser Senior Program Manager, TypeScript

' data-src=

Comments are closed. Login to edit/delete your existing comments

' data-src=

Are there any college-level textbooks on programming with TypeScript or do any universities offer programming courses using this language? It seems like a nice language to use as an introduction to programming.

' data-src=

From MDN https://developer.mozilla.org/zh-CN/docs/Web/API/Document/origin , document.origin only used in Chrome 41. and It may be removed in some newer version.


Logical assignment operators in Typescript

Portrait of Tom

Hi there, Tom here! As of writing, Typescript 4's stable release is imminent (August 2020) and with it are some very nice changes to come.

Typescript 4 ahead

One of those is the addition of logical assignment operators, which allow to use the logical operators with an assignment. As a reminder, here are the logical operators being used for the new logical assignment operators:

These new logical assignment operators themselves are part of the collection of compound assignment operators , which apply an operator to two arguments and then assign the result to the left side. They are available in many languages and now get enhanced in Typescript.

Code, please!

What does that mean? You probably already know a few compound assignment operators:

The new logical assignment operators now give you the ability to use your logical operator of choice for the same kind of assignment:

Note that these new operators were already available in JS and are also natively suppported by V8.

And that’s about it for one of Typescript 4’s great new features. Thanks for the quick read and I hope you could learn something!

expressFlow is now Lean-Forge

Logical OR assignment (||=)

The logical OR assignment ( x ||= y ) operator only assigns if x is falsy .


Logical OR assignment short-circuits , meaning that x ||= y is equivalent to:

No assignment is performed if the left-hand side is not falsy, due to short-circuiting of the logical OR operator. For example, the following does not throw an error, despite x being const :

Neither would the following trigger the setter:

In fact, if x is truthy, y is not evaluated at all.

Setting default content

If the "lyrics" element is empty, display a default value:

Here the short-circuit is especially beneficial, since the element will not be updated unnecessarily and won't cause unwanted side-effects such as additional parsing or rendering work, or loss of focus, etc.

Note: Pay attention to the value returned by the API you're checking against. If an empty string is returned (a falsy value), ||= must be used, so that "No lyrics." is displayed instead of a blank space. However, if the API returns null or undefined in case of blank content, ??= should be used instead.


Browser compatibility.

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Assignment operator overloading in TypeScript

I am writing a set of TypeScript classes that use inheritance to maintain a "Type" hierarchy (for want of a better phrase).

Say for example I have a base class...

and then I derive other classes from this...

So far so good...but lets say, now I want to be able to assign something to my Child class directly, like so:

TypeScript currently throws up a compiler/syntax error...

Cannot convert string to Child

If I can assign strings to String (which is equally, just a prototype, as is my Child class), how do I go about overloading the assignment operator of my class to accept strings?

EDIT: I tried this...

...still, it does not have the desired effect.

Speaking from a C# background, I guess I'm trying to achieve the equivalent of...

Matthew Layton's user avatar

In a class-based language you would normally accept parameters in the constructor, like this:

Fenton's user avatar

Your Answer

Sign up or log in, post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service , privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged javascript typescript ecmascript-5 or ask your own question .

Hot Network Questions

assignment operators typescript

Your privacy

By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy .


  1. assignment-operators

    assignment operators typescript

  2. expressFlow

    assignment operators typescript

  3. Assignment Operators in TypeScript

    assignment operators typescript

  4. Short Circuiting Assignment Operators in Typescript 4.0 & Angular 11

    assignment operators typescript

  5. Assignment Operator in JavaScript

    assignment operators typescript

  6. Assignment Operators ~ Computer Languages

    assignment operators typescript


  1. 10- Javascript Assignment Operators

  2. C language tutorial for loop while loop do..while loop assignment operators

  3. C# Fundamentals

  4. Assignment Operators

  5. JavaScript Assignment Operators #shorts #javascript

  6. assignment operators in #javascript #shorts


  1. TypeScript: Playground Example - Logical Operators and Assignment

    Logical Operators and Assignment Logical Operators and Assignment are new features in JavaScript for 2020. These are a suite of new operators which edit a JavaScript object. Their goal is to re-use the concept of mathematical operators (e.g. += -= *=) but with logic instead.

  2. TypeScript: Documentation - Variable Declaration

    var declarations. Declaring a variable in JavaScript has always traditionally been done with the var keyword. var a = 10; As you might’ve figured out, we just declared a variable named a with the value 10. We can also declare a variable inside of a function: function f() {. var message = "Hello, world!";

  3. Announcing TypeScript 4.0 - TypeScript

    TypeScript 4.0 improves the inference process for rest parameters and rest tuple elements so that we can type this and have it “just work”. type Arr = readonly unknown[]; function partialCall<T extends Arr, U extends Arr, R>( f: (...args: [...T, ...U]) => R, ...headArgs: T) { return (...tailArgs: U) => f(...headArgs, ...tailArgs) }

  4. Typescript 4 enhances the compound assignment operators

    You probably already know a few compound assignment operators: // Addition, Subtraction, Multiplication, Division x += y; x -= y; x *= y; x /= y; The new logical assignment operators now give you the ability to use your logical operator of choice for the same kind of assignment:

  5. Assignment (=) - JavaScript | MDN - Mozilla

    The assignment ( =) operator is used to assign a value to a variable. The assignment operation evaluates to the assigned value. Chaining the assignment operator is possible in order to assign a single value to multiple variables. Try it Syntax x = y Examples Simple assignment and chaining

  6. Why are logical assignment (&=) operators disallowed in ...

    In TypeScript you could conceivably create an &&= operator but the && operator uses short-circuit evaluation where evaluation stops as soon the result is known which means that the semantic of x &&= y becomes a bit clouded. Share Follow edited Jul 31, 2017 at 14:51 answered Mar 6, 2016 at 13:57 Martin Liversage 103k 22 204 251

  7. Logical OR assignment (||=) - JavaScript - Mozilla

    Description Logical OR assignment short-circuits, meaning that x ||= y is equivalent to: x || (x = y); No assignment is performed if the left-hand side is not falsy, due to short-circuiting of the logical OR operator. For example, the following does not throw an error, despite x being const: const x = 1; x ||= 2;

  8. javascript - Assignment operator overloading in TypeScript ...

    Assignment operator overloading in TypeScript Ask Question Asked 10 years ago Modified 10 years ago Viewed 3k times 2 I am writing a set of TypeScript classes that use inheritance to maintain a "Type" hierarchy (for want of a better phrase). Say for example I have a base class... class Parent { } and then I derive other classes from this...