TypeScript tutorial

Typescript exercises, typescript tuples, typed arrays.

A tuple is a typed array with a pre-defined length and types for each index.

Tuples are great because they allow each element in the array to be a known type of value.

To define a tuple, specify the type of each element in the array:

As you can see we have a number, boolean and a string. But what happens if we try to set them in the wrong order:

Even though we have a boolean , string , and number the order matters in our tuple and will throw an error.

Readonly Tuple

A good practice is to make your tuple readonly .

Tuples only have strongly defined types for the initial values:

You see the new valueTuples only have strongly defined types for the initial values:

To learn more about access modifiers like readonly go to our section on them here: TypeScript Classes .

If you have ever used React before you have worked with tuples more than likely.

useState returns a tuple of the value and a setter function.

const [firstName, setFirstName] = useState('Dylan') is a common example.

Because of the structure we know our first value in our list will be a certain value type in this case a string and the second value a function .

Get Certified!

Named tuples.

Named tuples allow us to provide context for our values at each index.

Named tuples provide more context for what our index values represent.

Destructuring Tuples

Since tuples are arrays we can also destructure them.

To review destructuring check it out here .

Test Yourself With Exercises

The order of value types does not matter for Tuples:

Start the Exercise

Get Certified

COLOR PICKER

colorpicker

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: [email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail: [email protected]

Top Tutorials

Top references, top examples, get certified.

Tuples in TypeScript: A Complete Guide

TypeScript enhances JavaScript’s capabilities by including types and various other features, one of which is tuples. Tuples are fixed-size arrays where each element can be of a distinct type. This guide covers everything you need to know about tuples in TypeScript, complete with practical examples.

Introduction to Tuples

In TypeScript, a tuple is a type that allows you to express an array with a fixed number of elements whose types are known, but do not necessarily have to be the same. Compared to arrays, which typically have elements of a single type, tuples provide the flexibility of having multiple types in one structured collection.

Declaring and Initializing Tuples

Creating tuples in TypeScript is straightforward. Here’s how you can declare and initialize a tuple.

This tuple specifies that the first element is a number, the second is a string, and the third is a boolean. The sequence in which you declare the types is how TypeScript understands and enforces them.

Accessing Tuple Elements

Once a tuple is declared, you can access its elements by using their index, just like an array.

Tuple Operations

Tuples in TypeScript behave like arrays in many ways, meaning you can use array methods on them. Here’s how you can manipulate tuples with methods like push() and pop() .

Types for Tuples

Advanced tuple usage includes optional elements, read-only tuples, and rest elements with spread syntax.

Tuple with Rest Elements

Tuples in TypeScript can use the rest element syntax to specify zero or more elements of a certain type.

Type Assertion with Tuples

You can use type assertion to treat an array as a tuple if TypeScript does not infer the tuple type automatically.

Generic Tuples

TypeScript’s generic tuples allow you to create reusable tuple types with generic placeholders.

Destructuring Tuples

Tuple destructuring works similarly to array destructuring, letting you unpack the elements into separate variables.

When to Use Tuples

Tuples are particularly useful when you need to return multiple values from a function or when you want to model a set of values as a single entity without creating a formal class or interface.

This comprehensive guide delves into what tuples are, how to declare and manipulate them, and their practical applications. Armed with this knowledge, you can now effectively use tuples in your TypeScript code to write cleaner and more precise type definitions.

Next Article: How to Compile TypeScript in Browser Environment

Previous Article: How to Properly Use '!' (Exclamation Mark) in TypeScript

Series: The First Steps to TypeScript

Related Articles

  • TypeScript Function to Convert Date Time to Time Ago (2 examples)
  • TypeScript: setInterval() and clearInterval() methods (3 examples)
  • TypeScript sessionStorage: CRUD example
  • Using setTimeout() method with TypeScript (practical examples)
  • Working with window.navigator object in TypeScript
  • TypeScript: Scrolling to a specific location
  • How to resize the current window in TypeScript
  • TypeScript: Checking if an element is a descendant of another element
  • TypeScript: Get the first/last child node of an element
  • TypeScript window.getComputerStyle() method (with examples)
  • Using element.classList.toggle() method in TypeScript (with examples)
  • TypeScript element.classList.remove() method (with examples)

Search tutorials, examples, and resources

  • PHP programming
  • Symfony & Doctrine
  • Laravel & Eloquent
  • Tailwind CSS
  • Sequelize.js
  • Mongoose.js

Home » TypeScript Tutorial » TypeScript Tuple

TypeScript Tuple

Summary : in this tutorial, you’ll learn about the TypeScript Tuple type and its usage.

Introduction to TypeScript Tuple type

A tuple works like an array with some additional considerations:

  • The number of elements in the tuple is fixed.
  • The types of elements are known, and need not be the same.

For example, you can use a tuple to represent a value as a pair of a string and a number :

The order of values in a tuple is important. If you change the order of values of the skill tuple to [5, "Programming"] , you’ll get an error:

For this reason, it’s a good practice to use tuples with data that are related to each other in a specific order.

For example, you can use a tuple to define an RGB color that always comes in a three-number pattern:

For example:

The color[0] , color[1] , and color[2] would be logically mapped to Red , Green and Blue color values.

Optional Tuple Elements

Since TypeScript 3.0, a tuple can have optional elements specified using the question mark (?) postfix.

For example, you can define an RGBA tuple with the optional alpha channel value:

Note that the RGBA defines colors using the red, green, blue, and alpha models. The alpha specifies the opacity of the color.

  • A tuple is an array with a fixed number of elements whose types are known.

Advisory boards aren’t only for executives. Join the LogRocket Content Advisory Board today →

LogRocket blog logo

  • Product Management
  • Solve User-Reported Issues
  • Find Issues Faster
  • Optimize Conversion and Adoption
  • Start Monitoring for Free

Exploring use cases for TypeScript tuples

typescript tuple assignment

Editor’s note: This guide to tuple use cases in TypeScript was last updated by Ukeje Goodness on 14 June 2023 to reflect recent changes to TypeScript. This update also includes new sections on the benefits of using tuples and best practices. To learn more about arrays in TypeScript, check out our guide to understanding flatMap() .

Exploring Use Cases of TypeScript's Tuples

Tuples extend the capabilities of the array data type. With tuples, we can easily construct special kinds of arrays, where elements are of fixed types with respect to an index or position. Due to the nature of TypeScript, these element types are known at the point of initialization. With tuples, we can define the data type that can be stored in every position in an array.

In this tutorial, we will cover real-world use cases and applications for named tuples in TypeScript. We will learn the importance of this data type and why it is preferred in certain cases. At the end of the day, we will see how this data type contributes to the improvement of the TypeScript language in terms of allowing stricter rules as per improved documentation, maintainable code, and developer productivity.

Before we get started, readers should be familiar with the basics of TypeScript and types in general. To learn more about this topic, check this section of TypeScript’s documentation. Now, let’s get started.

Jump ahead:

What are named tuples?

Benefits of using tuples, arrays with multiple data types, using tuples in rest parameters, spread expressions with tuples, destructure values, tips for creating meaningful and reusable tuple types, mistakes to avoid while using tuples, what are tuples.

Tuples are like advanced arrays with extra features that ensure type safety, particularly when we need to account for a list containing a fixed number of elements with multiple known types.

The major difference between arrays and tuples is that when we assign values to a tuple, these values must match the types defined in the tuple declaration in the same order. On the other hand, arrays can support multiple types with the any type or the bitwise OR ( | ) operator, but the order or structure of the elements doesn’t come into play.

Named tuples provide a structured approach for defining data with named properties. Named tuples combine the benefits of arrays and objects to clearly and concisely represent data points. Additionally, named tuples enhance code readability and make your intentions explicit by assigning names to the properties.

To define a named tuple in TypeScript, you’ll use a combination of square brackets and type annotations to specify the names and types of the properties. Here’s how you can define named types in TypeScript:

You’ve defined a named tuple MyNamedTuple with three properties: name of type string , age of type number , and isAdmin of type boolean . The order of the properties in the type definition determines the order of elements in the tuple on instantiation.

Once you have defined a named tuple type, you can declare and initialize variables of that type by assigning values to the properties like this:

You declared a variable person of the MyNamedTuple type and assigned values to it. The order of values corresponds to the order of properties defined in the named tuple type.

There are numerous benefits of using tuples in your TypeScript programs. First, tuples are fixed-length sequences that allow you to define an ordered collection of elements. Tuples are handy when you need to represent a sequence of values such as coordinates ( x , y ) or RGB color values ( red , green , blue ). The fixed length helps ensure you have the right number of elements in the tuples.

Additionally, you can easily destructure tuples to extract individual elements, allowing you to conveniently assign each element to a separate variable with a single line of code. Destructuring tuples can improve readability, especially when working with functions that return multiple values.

Also, tuples share some similarities with arrays; you can perform array-like operations on them. You can access individual elements by their index, iterate over them with loops and use methods like map , filter , and reduce . However, unlike arrays, tuples have a fixed length, which ensures that the structure of the tuple remains intact. Here’s an example:

Here’s the result of running popular array operations on the tuples:

Example of TypeScript Tuples Running an Array

Tuples are preferred over arrays due to the advantages and features of tuples. Tuples enforce fixed lengths, provide type safety, and allow heterogeneous data. TypeScript supports structural pattern matching on tuples and enables concise function signatures.

Destructuring assignments, read-only properties, and memory efficiency are additional benefits. Type inference and named tuple elements make tuples powerful for structured data.

Over 200k developers use LogRocket to create better digital experiences

typescript tuple assignment

Introducing array and tuple data types

Before we begin our journey into exploring use cases for tuples in TypeScript, let’s briefly explore some simple cases where arrays can be used and how tuples can fit in perfectly well — and even better — in the same scenario.

In TypeScript, we can declare an array of a particular data type. For example, we can declare an array of numbers by specifying the type of that element followed by square brackets: [] . Let’s see how to do so:

As we can see from the example above, to ensure type safety (which allows for easier annotation and documentation of our code), we need to use arrays, which allow for cases like this where we have lists of a particular data type. This, in fact, is the essence of a typed language like TypeScript.

For arrays with multiple data types, we can use the any type or the | (bitwise OR) operator. However, in this case, the order of the data is not set in stone. Let’s see an example below:

From the example above, we can decide to pass the number before the string, and it still works. The order in which we pass the data when the array is instantiated does not matter in this case, as we have a combination of the types specified. This is exactly what tuples aim to solve.

With tuples, we can have a list of multiple data types whereby the order in which we pass the data type must conform to the order when the tuple was declared. In essence, the structure of the tuple needs to stay the same. Let’s see an example to understand this concept better:

In the example above, we can see that we have declared a tuple with two basic data types: string and number . Note that when we call the tup variable, we must also pass the element types in the order they are declared. Essentially, we can’t have a number at index 0 and a string at index 1 , like so:

If we had done so, we would get the error shown below:

As we can see from the earlier examples above, we are declaring a number array and initializing it with values. This works as long as we are dealing only with element types that are numbers. To account for arrays with multiple data types, we can use the any type or | operator, although in this case, the order or structure of the data is not guaranteed, which might not be what we want.

With tuples, however, we can ensure strictness with respect to the data types and the order of the data we intend to pass. Tuples allow for specifying known type boundaries around element types with a fixed number of elements.

TypeScript tuples use cases

Since tuples allow us to define both fixed types and order in an array, they are best when working with data that are related to each other in a sequential way (where order is important). That way, we can easily access the elements in a predetermined manner, making our desired responses predictable in behavior.

Below, we will be exploring some more use cases of tuple types in TypeScript based on releases up to the v4.2 release , which will generally revolve around extracting and spreading parameter lists in function signatures.

The REST parameter syntax collects parameters into a single array variable and then expands them. With the recent TypeScript release, we can now expand REST parameters with the tuple type into discrete parameters. What this means is that when a tuple type is used as a REST parameter, it gets flattened into the rest of the parameter list.

In simple terms, when a REST parameter is a tuple type, the tuple type can be expanded into a sequence of parameter lists.

Consider the example below:

The REST parameter expands the elements of the tuple type into discrete parameters. When the function is called, args , which is represented as a REST parameter, is expanded to look exactly like the function signature below:

Therefore, the REST parameter syntax collects an argument overflow into either an array or a tuple. In summary, a tuple type forces us to pass the appropriate types to the respective function signatures. TypeScript v4.2 added the ability to spread on leading or middle elements. This is handy since you can use REST parameters to create variadic functions on leading or middle parameters as thus:

The processMatches function accepts a variadic parameter with the ... spread syntax. The parameter is of type [...Matches[], string] , meaning it expects two or more tuples of type Matches followed by a string. Here’s a visual:

typescript tuple assignment

The spread syntax expands the elements of an array or object into its element. The spread operator can also expand the elements of a tuple. When a function call includes a spread expression of a tuple type as an argument, the spread expression is expanded as a sequence of arguments corresponding to the element of the tuple type. Let’s see an example below:

N.B. , as we can see from the above example, we have declared a tuple type and passed it as a parameter to the function signature.

When the function is called, we can either pass the arguments as literals or via their respective indices. However, using the spread operator is a fast and clean option for passing a tuple as an argument to a function call. Due to the nature of spread operators, the parameters are expanded as a list of arguments corresponding to the elements of the tuple type.

Because tuples are arrays under the hood, we can destructure them just like we would an array. It is important to note that the destructuring variables get the types of the corresponding tuple elements. Let‘s look at an example:

TypeScript tuples best practices

While tuples have their advantages, it’s essential to consider the trade-offs before using them. Tuples are less flexible than arrays and objects, and modifying or extending tuples can be cumbersome. You might find arrays or objects more suitable if your data structure requires frequent modifications or additional properties.

Creating well-defined and reusable tuple types is crucial for maintaining clarity and reducing code duplication. Let’s discuss some tips to consider when defining and using tuple types in TypeScript. First, make sure that you assign meaningful names to the elements within your tuples to enhance readability and help others understand the purpose of each value. For example, instead of using [x, y] for coordinates, consider [latitude, longitude] .

Also, TypeScript’s type inference system can automatically infer tuple types based on their assigned values. Instead of explicitly defining types, you should rely on type inference to reduce redundancy and improve code maintainability. If some elements within a tuple are optional, use union types to indicate possible absence. The flexibility ensures your tuple types accommodate multiple scenarios.

When tuples are complex or reused across multiple parts of your codebase, consider abstracting them into interfaces or type aliases to reusability, improve code readability, and allow for more accessible modifications and extensions in the future. By following these tips, you can create meaningful and reusable tuple types that enhance the clarity and maintainability of your TypeScript programs.

There are common pitfalls that developers should be aware of to avoid potential issues. In this section, we’ll cover some common mistakes to avoid when working with tuples. Tuples are immutable by default. Attempting to modify the values of a tuple will result in a compilation error. Avoid changing tuple elements directly; create new tuples with the desired modifications.

Keep in mind that tuples rely on the order of their elements to maintain their structure. Accidentally reordering elements can introduce bugs that are difficult to spot. To prevent this, use clear and descriptive variable names and use destructuring or named tuple elements to access values by name instead of relying solely on their order.

Finally, overusing tuples can make your code harder to understand and maintain. Consider using objects or arrays if a data structure requires frequent modifications. Avoiding these mistakes will help you effectively harness the power of TypeScript tuples and reduce potential code bugs.

TypeScript tuples are like arrays with a fixed number of elements. They provide us with a fixed-size container that can store values of multiple types, where order and structure are very important. This data type is best used when we know exactly how many types we want to allow in an array. As we know, assigning an index outside of the original defined length will result in an error by the TypeScript compiler.

Note that while it is possible to modify the values of tuple elements via their indices, we must ensure to match the types provided when the tuple variable was declared. This is because we can’t alter the type or even the size of elements in the tuple once declared.

With the features we have highlighted in this post, it becomes possible to design strongly typed higher-order functions that can transform functions and their parameter lists, and in essence, ensure a robust, well-documented, and maintainable codebase, which is at the very heart of why we use TypeScript.

LogRocket : Full visibility into your web and mobile apps

LogRocket Dashboard Free Trial Banner

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

Try it for free .

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on Reddit (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to share on Facebook (Opens in new window)
  • #typescript

typescript tuple assignment

Stop guessing about your digital experience with LogRocket

Recent posts:.

Using Pavex For Rust Web Development

Using Pavex for Rust web development

The Pavex Rust web framework is an exciting project that provides high performance, great usability, and speed.

typescript tuple assignment

Using the ResizeObserver API in React for responsive designs

With ResizeObserver, you can build aesthetic React apps with responsive components that look and behave as you intend on any device.

typescript tuple assignment

Creating JavaScript tables using Tabulator

Explore React Tabulator to create interactive JavaScript tables, easily integrating pagination, search functionality, and bulk data submission.

typescript tuple assignment

How to create heatmaps in JavaScript: The Heat.js library

This tutorial will explore the application of heatmaps in JavaScript projects, focusing on how to use the Heat.js library to generate them.

typescript tuple assignment

Leave a Reply Cancel reply

TypeScript - Tuples

TypeScript introduced a new data type called Tuple. Tuple can contain two values of different data types.

Consider the following example of number, string and tuple type variables.

In the above example, we have defined a variable empId as number type and empName as string type with values. Here, we declared and assigned two variables to id and name of an employee. The same thing can be achieved by using a single tuple type variable. employee is the tuple type variable with two values of number and string type. Thus, removing the need to declare two different variables.

A tuple type variable can include multiple data types as shown below.

You can declare an array of tuple also.

TypeScript generates an array in JavaScript for the tuple variable. For example, var employee: [number, string] = [1, 'Steve'] will be compiled as var employee = [1, "Steve"] in JavaScript.

Accessing Tuple Elements

We can access tuple elements using index, the same way as an array. An index starts from zero.

Add Elements into Tuple

You can add new elements to a tuple using the push() method.

This is allowed because we are adding number and string values to the tuple and they are valid for the employee tuple.

Now, let's try to add a boolean value to the tuple.

The above example will throw the following error:

We get an error saying that adding a boolean value to a tuple of type 'number | string' is not permitted. Hence, a tuple declared as 'number | string' can store only number and string values.

The tuple is like an array. So, we can use array methods on tuple such as pop(), concat() etc.

typescript tuple assignment

We are a team of passionate developers, educators, and technology enthusiasts who, with their combined expertise and experience, create in -depth, comprehensive, and easy to understand tutorials.We focus on a blend of theoretical explanations and practical examples to encourages hands - on learning. Visit About Us page for more information.

Learn TypeScript

Using tuples.

In this lesson, we will learn what tuples are and how we can use them in TypeScript.

Understanding a tuple

A tuple can be thought of as an array with a fixed number of elements. Some of the hooks in React return tuples.

One example is the useState hook:

Tuples are useful when we want to store multiple bits of data. Tuples are a little more concise than an object but aren't as self-documenting as objects. So, tuples are nice for small and obvious data structures.

The tuple type doesn't exist in JavaScript. The closest we have are arrays, but there is no way of enforcing the number of elements and each element's type.

Creating a simple tuple

Is it possible to use TypeScripts rich type system to create tuples? Let's find out with an example.

  • Open the TypeScript playground by clicking the link below:
  • Make sure the TypeScript version in the Playground is set to at least v4 and paste the code from below:

The code contains an array containing a person's first name followed by a numeric score.

We want tomScore to only have two array elements with the first being a string and the second being a number . Has TypeScript inferred an appropriate type for this.

Typescript can't infer the correct type for fixed tuples. So, we will always need to use a type annotation for tuples.
  • Try to figure out what an appropriate type annotation would be for tomScore .

So, a fixed tuple type annotation can be defined by specifying the types of the elements in an array structure: [type1, type2, ...]

Labelling elements

An mentioned earlier, an issue with tuples is that it isn't obvious what data should be placed in its elements. TypeScript 4.0 eases this problem with the ability to label elements within a tuple.

The syntax for a tuple type annotation with labels is below:

  • Change the type annotation on tomScore to have element label.

Creating open-ended tuples

An open-ended tuple is where its items have some structure, but the number of elements isn't fixed. An example is a person's first name with numerous scores like below:

We can specify the type for the above example as follows:

The ...number[] is a rest element , and it means that we can have a varying amount of number elements at the end of the structure.

If we want to specify labels on this tuple, we can do so as follows:

Notice the that the ... is placed before the label rather than the type.

  • Create a statement in the code editor that declares a variable called benScores with the above structure including labels. Assign the variable to value ["Ben", 50, 75, 85] .
  • Now try and set benScores to a tuple that has a string score:

We see that the TypeScript type checking process picks this up as an error as we expect:

Tuple type error

Typescript tuples are a convenient way of strongly-typing small and obvious data structures. It is essential to use a type annotation with these rather than rely on type inference.

Further information about the tuple type can be found in the TypeScript handbook .

In the next lesson, we will learn about the never type.

Did you find this lesson useful?

Using arrays, using the never type, on this page.

Learn tuples in TypeScript, including named element types, tuple destructuring, optional elements, and spread syntax for variable-sized tuples.

Introduction to tuples in TypeScript

  • Tuple destructuring
  • Optional tuple elements
  • Tuples and spread syntax
  • Object destructuring

Tuples are a method of defining a type that has a finite number of unnamed properties, with each property having an associated type. When using a tuple, all of the properties must be provided.

This can best be explained in an example as follows:

Get hands-on with 1200+ tech skills courses.

  • Course List
  • Introduction to TypeScript
  • Environment Setup
  • Workspace & first app
  • Basic Syntax
  • Variables & Constants
  • Conditional Control
  • if, else if, else & switch
  • Iteration Control
  • for, while, do-while loops
  • Intermediate
  • Map Collections
  • Object Oriented Programming
  • OOP: Classes & Objects
  • OOP: Standalone Objects
  • OOP: Constructors
  • OOP: Property Modifiers
  • OOP: Access Modifiers
  • OOP: Parameter Properties
  • OOP: Getters & Setters
  • OOP: Static methods
  • OOP: Index Signatures
  • OOP: Inheritance
  • OOP: Composition
  • Compilation Config (tsconfig.json)

TypeScript Tuples Tutorial

In this TypeScript tutorial we learn how to store multiple values with different types in the tuple data container.

Tuples in TypeScript are almost identical to arrays, so this lesson will be fairly easy. We cover declaring and initializing tuples, accessing and mutating their values, and adding and removing elements.

Lastly, we discuss how to destructure a tuple.

  • What is a tuple

How to initialize a tuple literal

How to access tuple elements with the indexer, how to access tuple elements in a loop, how to change tuple elements, how to add tuple elements, how to remove tuple elements, how to destructure a tuple, summary: points to remember.

A tuple is similar to an array in that it can store multiple values in a single container.

But, whereas an array can only store values of a single type, a tuple can store values of different types.

Like an array, the most straightforward way to create a tuple is by initializing a tuple literal.

To create a tuple literal, we start with a unique name, followed by the assignment operator and open and close square brackets. Inside the square brackets we add one or more values, separating them with a comma.

note It’s exactly like an array, except we don’t specify a type.

Similar to an array, the tuple is like a table with a single row, but multiple columns.

To access a tuple element, we use the indexer. Just like an array, each element in a tuple has a corresponding number.

These numbers form the index. When we want to access a specific element, we provide the element’s corresponding index number between open and close square brackets.

TypeScript allows us to access tuple elements in a loop, providing there is some sort of counter to iterate through the elements.

We also have access to the .length property if we need to know how many elements there are in a tuple.

To use the property, we specify the tuple name, followed by a dot operator and the length keyword.

Tuples in TypeScript are mutable, which means we can change their data at runtime.

To change the value of a tuple element, we refer to its index to access the element and then assign it a new value. We can change from one type to another.

In the example above, we change the values of both elements. The second element used to be a number, but we changed it to a string.

To add elements to a tuple, we use the built-in .push() method. It will push a value onto the end of the tuple.

To push an element, we write the tuple name, followed by a dot operator and push . Then, we specify the value we want to add as an argument.

In the example above, we push a single value into a new element at the end of the tuple.

We can push more than one element into the tuple by separating the values we want to push with a comma. The values will be added in the same order we specify.

In the example above, we add 3 more elements to the tuple.

When we look at the list printed in the console, we can see that the elements were added in the same sequence.

TypeScript provides us with three methods to remove elements from an tuple, depending on where the element is.

  • pop() - Removes an element from the end of the array.
  • shift() - Removes an element from the start of the array.
  • splice() - Removes an element at a specific index.

To remove an element from the end of a tuple, we use the .pop() method without any arguments.

The pop() method will return the value of the element which it just removed.

To remove an element from the start of a tuple, we use the .shift() method, without any arguments.

It works exactly the same as .pop() , except it removes the element at the start instead of the end. It will also return the value that it removed.

With the .splice() method we can remove an element, or multiple elements, at a specific index.

It requires two arguments. The first is the index where we want to start removing elements, the second is the number of elements to remove.

In the example above, we remove 2 elements starting at index 1, “John”. This will remove “Doe” and 32.

The .splice() method also returns the element(s) it removed.

Destructuring means that we break up the structure of an entity. TypeScript supports destructuring tuples.

In the example above, we assign the values of the tuple into separate variables.

  • A tuple is a data container that can store multiple values of different types.
  • We use [] (square brackets) to initialize a tuple with values separated by a comma.
  • We do not add a type when initializing a tuple.
  • To access individual elements in a tuple, we refer to its position in the tuple index.
  • Tuples are mutable and element values can be changed by assigning new values to them.
  • We append new elements to a tuple with the .push() method.
  • We remove elements with .pop() , .shift() and .splice() .
  • Tuples can be destructured.
  • Initialize a tuple literal
  • Access tuple elements with the indexer
  • Access tuple elements in a loop
  • Change tuple elements
  • Add tuple elements
  • Remove tuple elements
  • Destructure a tuple

Assignments

TypeScript narrowing using assignments is a way to narrow the type of a variable based on the value assigned to it. When a variable is assigned a value, TypeScript infers its type based on the assigned value, and it narrows the type of the variable to match the inferred type.

  • DSA with JS - Self Paced
  • JS Tutorial
  • JS Exercise
  • JS Interview Questions
  • JS Operator
  • JS Projects
  • JS Examples
  • JS Free JS Course
  • JS A to Z Guide
  • JS Formatter
  • TypeScript Tutorial

TypeScript Basics

  • Introduction to TypeScript
  • Difference between TypeScript and JavaScript
  • How to install TypeScript ?
  • Hello World in TypeScript
  • How to execute TypeScript file using command line?
  • Variables in TypeScript
  • What are the different keywords to declare variables in TypeScript ?
  • Identifiers and Keywords in TypeScript

TypeScript primitive types

  • Data types in TypeScript
  • TypeScript Numbers
  • TypeScript String
  • Explain the concept of null and its uses in TypeScript

TypeScript Object types

  • What are TypeScript Interfaces?
  • TypeScript class
  • How enums works in TypeScript ?

TypeScript Tuples

Typescript other types.

  • What is any type, and when to use it in TypeScript ?
  • How to Create an Object in Typescript ?
  • What is an unknown type and when to use it in TypeScript ?
  • Explain the purpose of never type in TypeScript

TypeScript combining types

  • TypeScript Union
  • What are type aliases and how to create it in Typescript ?

TypeScript Assertions

  • Explain Type assertions in TypeScript

TypeScript Functions

  • How to write a function in Typescript ?
  • How to achieve function overloading in TypeScript ?
  • Explain the arrow function syntax in TypeScript
  • TypeScript | toPrecision() Function
  • TypeScript | toFixed() Function
  • TypeScript | toLocaleString() Function
  • TypeScript | toString() Function

TypeScript interfaces and aliases

Typescript classes.

  • How to Extend an Interface from a class in TypeScript ?
  • How to use getters/setters in TypeScript ?
  • TypeScript Inheritance
  • When to use interfaces and when to use classes in TypeScript ?
  • Generics Interface in typescript
  • How to use property decorators in TypeScript ?

TypeScript modules

  • What are the Modules in Typescript ?
  • How to import a module in Typescript ?
  • TypeScript Arrays
  • TypeScript | Array push() Method
  • TypeScript Array slice() Method
  • TypeScript Array splice() Method
  • TypeScript Array reverse() Method
  • TypeScript Array reduce() Method
  • TypeScript Array concat() Method
  • TypeScript Array some() Method
  • TypeScript | Array shift() Method
  • TypeScript | Array map() Method
  • TypeScript | Array indexOf() Method
  • TypeScript | Array filter() Method
  • TypeScript | Array reduceRight() Method
  • TypeScript | Array join() Method
  • TypeScript | Array unshift() Method
  • TypeScript | Array sort() Method
  • TypeScript | Array lastIndexOf() Method
  • TypeScript | Array pop() Method
  • TypeScript | Array forEach() Method
  • TypeScript Array toString() Method

Typescript String

  • TypeScript | String Constructor Property
  • TypeScript String toLowerCase() Method
  • TypeScript String toString() Method
  • TypeScript | String toLocaleUpperCase() Method
  • TypeScript | String substring() Method
  • TypeScript | String substr() Method
  • TypeScript String split() Method
  • TypeScript | String valueOf() Method
  • TypeScript | String replace() Method
  • TypeScript | String toLocaleLowerCase() Method
  • TypeScript | String lastIndexOf() Method
  • TypeScript | String slice() Method with example
  • TypeScript | String concat() Method
  • TypeScript | String indexOf() Method
  • TypeScript | String Length Property
  • TypeScript | String search() Method
  • TypeScript String Prototype Property
  • TypeScript | String charCodeAt() Method

TypeScript Exercises

  • TypeScript Exercises, Practice Questions and Solutions

As we know array consists of values of homogeneous (same) types but sometimes when we need to store a collection of a different types values in a single variable, then we will go with Tuples . They are just like structure in C programming and can also be passed as parameters in a function call. Tuples may be one or more than one types of data (like number with string or string with number and so on).

  • To denote a multi-dimensional coordinate system the term used is tuple in abstract mathematics.
  • In JavaScript we doesn’t have tuples as data types, but in typescript Tuples facility is available.
[501, ‘welcome’, 105, ‘Mohan’]

Declaration and initialization of a tuple separately by initially declaring the tuple as an empty tuple in Typescript. Example:

Accessing tuple Elements With the help of index basis we can read or access the fields of a tuples, which is the same as an array. An index starts from zero too. 

We can declare heterogeneous datatypes in tuples like: number and string simultaneously.

  Example

Name of the Employee is : Vivek Singh Age of the Employee is : 22 Vivek Singh is working in Microsoft

Operations on Tuple A tuple has two operations:

Push() To add an element to the tuple with push operation. Example

[1, ‘Steve’, 2, ‘Bill’]

This type of declaration is allowed in tuples because we are adding number and string values to the tuple and they are valid for the employee tuple. 

Items: Vivek Singh, 22, Honesty Length of Tuple Items after push: 4 Items: Vivek Singh, 22, Honesty, 10001

To add an element to the tuple with push operation. 

Items: Mohit Singh, 25, geeksforgeeks, 10001 Length of Tuple Items after pop: 3 Items: Mohit Singh, 25, geeksforgeeks

Update or Modify the Tuple Elements We need to use the index of the fields and assignment operator for modifying the fields of tuple. It can be shown in the following example. Example

Name of the Employee is: Ganesh Singh Age of the Employee is: 60 Ganesh Singh is working in TCS

Clear the fields of a Tuple Fields could be cleared but we cannot delete the tuple variables. To clear the fields of a tuple, assign it with an empty tuple field set as shown below:

In TypeScript, To break up the structure of an entity by destructuring. 

Rohit Sharma 25

Passing Tuple to Functions

JavaTpoint 101 Abhishek

Following shown is the code snippet which will help us to understand Tuple creation in TypeScript:-

Please Login to comment...

Similar reads.

  • Web Technologies

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

Narrowing Function Parameters With Rests And Tuples

TypeScript's provides several ways to describe the type of a function that can be called in multiple different ways. But the two most common strategies -function overloads and generic functions- don't help much with how the function's internal implementation understands the types of its parameters.

This article will walk through three techniques for describing a parameter type that changes based on a previous parameter. The first two allow using standard JavaScript syntax but aren't quite precise in describing the types inside the function. The third one requires using a ... array spread and [...] tuple type in a funky new way that gets the right types internally.

Dependent Parameter Types? What? ​

Suppose you wanted to write a function that takes in two parameters:

  • fruit : either "apple" or "banana"
  • an AppleInfo type if fruit is "apple" , or
  • a BananaInfo type if fruit is "banana"

In that function, the second parameter's type is different based on the first parameter.

An initial approach might be to declare the function's two parameters - fruit and info - as union types. In short:

That would allow calling the function with the right matched types, such as "apple" and an object matching AppleInfo . That might look something like this:

Two problems in that code block:

  • It requires manually as asserting info to the right type even when fruit 's type has been narrowed, such as within case "apple" .
  • Nothing prevents calling logFruit with mismatched types, such as "banana" and an object matching AppleInfo .

The logFruit function needs a way to indicate that info 's type is dependent on the type of fruit .

Using Function Overloads ​

One approach for describing a function as having multiple ways it can be called is with function overloads . To recap function overloads, TypeScript allows code to describe any number of call signatures just before a function's implementation. The function is then allowed to be called in ways matching any of those call signatures.

For example, this eitherWay can be called either with a number input to return a number or a string input to return a string :

Describing the logFruit function with overloads -let's call it logFruitOverload - would look something like declaring a signature for "apple" and a signature for "banana" :

This function overloads approach does improve on the first one around union types:

  • Calling logFruitOverload with "apple" permits passing an object matching AppleInfo as info .
  • Calling logFruitOverload with "banana" and an AppleInfo object is a type error.

But, the type of info inside the case "apple": is still AppleInfo | BananaInfo . You can see this by hovering your cursor or mouse over the info in info as AppleInfo . Explicit as assertions are still needed to access fruit-specific properties.

TypeScript isn't able to narrow the type of info even though the two overloads explicitly stated that each fruit string matched up with a specific interface. The function's implementation signature -which is what its internal implementation respects- didn't understand the relationship.

Using Generic Functions ​

Another attempt at type safety for this function might be to turn it generic. The type of info depends on the type of fruit ; therefore, using a type parameter for fruit would allow for narrowing the type of info based on the type of fruit .

This implementation declares a Fruit type parameter that must be one of the keys of an InfoForFruit interface ( "apple" | "banana" ), then declares that info must the corresponding InfoForFruit value under that Fruit key:

This generic version gives a friendlier error message in the case of calling logFruitGeneric with "banana" and the wrong shape of info. But TypeScript again unfortunately isn't able to narrow down the type of info inside case "apple" .

Using Rest Parameters ​

For a third and final attempt, let's combine three pieces of syntax:

  • Rest parameters : using a ... to allow any number of parameters as an array
  • Tuple types : restricting the type of an array to a fixed size, with an explicit type for element
  • Array destructuring assignment : taking the elements in an array and assigning them to local variables

This logFruitTuple version uses those three techniques to allow passing in fruit and info parameters adhering to the FruitAndInfo tuple type:

The function properly narrows info 's type based on fruit , and properly flags the incorrect call with "banana" and an AppleInfo -shaped object. Hooray!

Step-by-step, here's how that parameter works:

  • ... is a rest parameter, collecing any arguments may be passed to the function into an array
  • [fruit, info] collects the first two elements of that array, storing them in fruit and info variables, respectively
  • ["apple", AppleInfo]
  • ["banana", BananaInfo]

Putting it all together: the function accepts two parameters, and assigns them the type FruitAndInfo together. That's exactly what we wanted!

How It Works ​

TypeScript is smart enough that when elements of a tuple are narrowed, other elements of that same tuple are narrowed too. That's why TypeScript knows that if fruit is an "apple" inside logFruitTuple , it can narrow the type of info to AppleInfo .

You can isolate that smartness separately from function parameters. In the following snippet, when the destructured fruit variable is narrowed to "apple" , info is narrowed to AppleInfo :

logFruitTuple 's [fruit, info] parameter is typed as FruitAndInfo , so it benefits from the tuple types narrowing. Smart.

Named Tuples ​

Thanks to Emil van Galen on Twitter for noting the usage of named tuples!

One downside of the tuples approach is that, by default, arguments do not have names. The logFruitTuple function from earlier uses auto-generated __0_0 and __0_ when suggesting parameter names in editors:

You can work around this naming behavior by assigning explicit names to the tuple type's elements.

Putting fruit: and info: before each of the elements in the tuples will let TypeScript know to suggest those names in the function:

See Default rest parameter names to destructuring names when of an anonymous tuple on the TypeScript issue tracker for more details.

Which Should You Use? ​

It depends.

Most of the time, these kinds of complex function signatures are a sign of overly complicated code. Types that are difficult to represent in the type system can be difficult to work with because they can be conceptually complex. When possible, try to avoid needing this kind of function signature.

Technique Tradeoffs ​

If you must use one of these techniques, consider which one will cause your project's developer(s) the least pain in the future. Many TypeScript developers prefer to avoid function overloads because of how wacky they appear at first glance. Generic functions can also be intimidating to many TypeScript developers, though generally less so in cases such as this one that only have one type parameter.

... rest tuple parameters are a nifty trick that also run the risk of confusing developers. But the increased type safety internally may be worth that confusion. My recommendation would be to wait for a time that they're very well suited towards, try them out once, and see how they feel. You may find that you like them or you may not.

Wrapping arguments in an array and then immediately destructuring that array also runs a small risk of hurting runtime performance if used in a very commonly run path. Though, this performance hit is likely optimized to be zero or near-zero in most instances of the function. Always diagnose runtime performance problems before jumping to conclusions.

Alternative: Objects ​

Instead of wrestling with multiple function parameters, consider using a single object with multiple properties. Doing so would allow using techniques such as the following discriminated union to represent different allowed shapes.

Whichever strategy you choose, remember to keep the code as readable and straightforward to understand as possible. This quote from Brian Kerninghan applies to the type system as well as runtime code:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.

Happy typing!

Further Reading ​

  • Narrowing is covered in Learning TypeScript Chapter 3: Unions and Literals .
  • Object types and discriminated type unions are covered in Learning TypeScript Chapter 4: Objects .
  • Function overloads are covered in Learning TypeScript Chapter 5: Functions .
  • Generic functions are covered in Learning TypeScript Chapter 10: Generics .

Got your own TypeScript questions? Tweet @LearningTSbook and the answer might become an article too!

  • Dependent Parameter Types? What?
  • Using Function Overloads
  • Using Generic Functions
  • How It Works
  • Named Tuples
  • Technique Tradeoffs
  • Alternative: Objects
  • Further Reading

Named Tuple Type (Labeled)

Tuple types can include optional labels or names for each element. These labels are for readability and tooling assistance, and do not affect the operations you can perform with them.

TypeScript 関数型スタイルでバックエンド開発のリアル

typescript tuple assignment

TypeScript 関数型スタイルでバックエンド開発のリアル

TSKaigi 2024 のスライドです

typescript tuple assignment

More Decks by Naoya Ito

typescript tuple assignment

Other Decks in Programming

typescript tuple assignment

5ZQF4DSJQUؔ਺ܕελΠϧͰόοΫΤϯυ։ൃͷϦΞϧ גࣜձࣾ Ұٳ ҏ౻ ௚໵ 54,BJHJ

എܠ • ҏલʹʮ5zqf4dsjquλ࢖͍ؔ਺ܕϓϩάϥϛϯάدγͷ࣮૷ͱɺ৯ళ޲͚ۀ຿γεςϝ 4bb4 ͷ όοϋτϯυλ։ൃ͍ͯ͠δʯͱ͍͏ൃදλߦ͍·ͨ͠ • ʮؔ਺ܕɺܕλ࢖͍ͬͯ͘ͷ͸෼͔δɻͨͩɺξϓϧέʔγϣϯશମͷߏ੒ͷπϝʔδ͕෸͔ͳ͍ʯͱ ͍͏࣭໰λα͍͖ͨͩ͘·͢ •, %pnbjo.pefmjoh.bef'vodujpobm, υϝπϯφϒδσϋτλܕͱදݱ͢δɻ6ojpoܕλੵۃར༻ͯ͠ෆඞཁͳঢ়ଶλදݱ͠ͳ͍ υϝπϯπϕϯτʹαδφϒδσϋτͷঢ়ଶભҡ͸ؔ਺ద༻ https://www.slideshare.net/scottwlaschin/domain-modeling-made-functional-kandddinsky-2019, ͳ͓ɺॻ੶ͦͷ௨γʹ͸΍͍ͬͯͳ͍ • υϝπϯφϒδσϋτλܕͱදݱ͢δ ˠ͍͍ͷ • τϥʔʹαδ෼ذ͸ 3ftvmuܕͱѻ͍ɺτϥʔॲཧλ໌ࣔతʹ͢δ ˠ ͍͍ͷ •, 5zqf4dsjquͱɺͳμͳελπϧͱ࣮૷͍ͯ͠δ͔ • υϝπϯφϒδσϋτ͸ܕͱߏ଄λఆٛ͢δ – dmbttͱ͸ͳ͘ joufsgbdf • φϒδσϋτͷมߋ͸ʮؔ਺ద༻ʹαδঢ়ଶભҡʯͱͯ͠πϛϡʔλϒϧʹ͢δ – ʮφϒδσϋτͷ಺෦ঢ়ଶͷॻ͖׵໋͑ྩʯͱ͸ͳ͘ʮؔ਺ద༻, υϝπϯφϒδσϋτ͸ܕͱఆٛ͢δ export interface customer { id: customerid groupid: restaurantgroupid name:, 6ojpoܕλੵۃతʹར༻͢δ export type reservation = directreservation | sitereservation interface _reservation, ஋φϒδσϋτ // nominal な型 export type customerid = newtype<'customerid', string>, ஋φϒδσϋτ͸ίϯετϥϋλͱੜ੒ ࣦഊ͸ 3ftvmuͱฦ͢ export type color = newtype<'color', string> export, φϒδσϋτͷมߋ͸ʮؔ਺ద༻ʹαδঢ়ଶભҡʯͱ࣮ͯ͠૷͢δ ͋δঢ়ଶ tʹؔ਺ gλద༻ͯ͠ɺผͷঢ়ଶ tλಘδ // 顧客をアーカイブ状態にする export const archivecustomer, customer.archive() const archived = archivecustomer(customer) • ໋ྩతʹॻ͘ – φϒδσϋτͷ಺෦ঢ়ଶλॻ͖׵͑δ໋ྩλߦ͏͜ͱͱɺঢ়ଶλมխͤ͞δ –, ϣʔεέʔε͸ xpslgmpxͱ࣮ͯ͠૷͢δ 3ftvmuλฦؔ͢਺λ߹੒ͯ͠ұຊಓͷॲཧϑϩʔλ࡞δ 3bjmxbz0sjfoufe1sphsbnnjoh https://fsharpforfunandprofit.com/rop/, ϫʔϋϑϩʔͷͱ͋δαϒεςοϓ uuu ࣦഊͱͷ෼ذ͸ 3ftvmuͱදݱ // 予約リクエストから来店者情報を抽出 type extractactualvisitor = (command:, ϫʔϋϑϩʔʹ͓͚δঢ়ଶભҡλܕͱఆٛ͢δ interface unvalidatedcommand { kind: 'unvalidated' input: { groupid: restaurantgroupid, ұ࿈ͷαϒεςοϓλ߹੒͠ϫʔϋϑϩʔ ϣʔεέʔε λߏ੒͢δ type workflow = (command: unvalidatedcommand) => resultasync<importsitereservationevent[],, ϫʔϋϑϩʔλ (sbqi2-nvubujpo͔βݺͼ *0ͱαϯυπον͢δ builder.mutationfield('updatetablepattern', (t) => t.field({ type: updatetablepatternpayload, args:, σʔλϕʔε *0͸ 3fqptjupszύλʔϯ ͨͩͨͩ͠ͷؔ਺  export const findtagbyid = ({, ؔ਺ܕελπϧͱ΍ͬͯδͷ͸ओʹυϝπϯ૚ɻͦεҏ֎͸ैདྷ௨γͷ࡞γ (input, model) -> result(model,error) *0 joqvu mpbe *0 tbwf, https://www.slideshare.net/slideshow/pipeline-oriented-programming/250490001, *0ˠυϝπϯ૚ υϝπϯφϒδσϋτͷঢ়ଶભҡ ˠ*0 • ϣʔβʔ͔βͷೖྗɺσʔλϕʔε͔βͷφϒδσϋτͷऔಘɺอଘλ੍ޚ͢δͷ͸ (sbqi2- nvubujpo • σʔλϕʔε͔βͷφϒδσϋτͷऔಘɺอଘ͸ 3fqptjupszuuu, γεςϝશମͷ࣮૷͸ɺैདྷͷ࣮૷͔βͦε΄ͳมθβͳ͍ • ξϓϧέʔγϣϯશମ͸͜ε·ͱ௨γͷφχφϯξʔωςϋνϟʔ • υϝπϯϩπϡʔ͸ؔ਺ܕͱ͍ͬͯ΋ϙπϯτ͸ओʹͭͷέ – φϒδσϋτͷߏ଄λܕ joufsgbdf ͱදݱ͢δ –, ͳͥυϝπϯϩπϡʔλؔ਺ܕελπϧʹ͍ͨ͠ͷ͔ • ܕλ༗ޮʹར༻͍ͨ͠ – ੩తݕࠪʹد͍ͤͯ͘ͱʮಈ͔͞ͳ͍ͱ෼͔βͳ͍͜ͱʯ͕ݮδ – υϝπϯ૚ʹ͓͍ͯʮෆඞཁͳঢ়ଶଘࡏʯλݮβ͢ͱݎ࿚ʹͳδ uuu 6ojpoܕλੵۃར༻͍ͨ͠ •, ؔ਺ܕελπϧλར༻͍ͨͨ͠ίͷɺ*0෼཭ uuu φχφϯξʔωςϋνϟ • *0ґଘ͕͋δͱ͔ͦ͜βҷͮδࣜతʹखଓ͖త ໋ྩత ʹͳγ΍͍͢ • υϝπϯϩπϡʔλ *0ͱ෼཭͢δ͜ͱͱɺυϝπϯϩπϡʔλؔ਺ܕελπϧʹ͢δ༨஍͕ੜ·εδ, ໘౗ͳͱ͜ζ uuu 3ftvmuܕύζϧ export const tag = (input: taginput): result<tag,, ʮίϯςφʹೖͬͨจ຺͖ͭͷ஋ʯλѻ͏ɺ૊έࠐέͷػೳ͕͋δݴޠͳβuuu ͜ͷखͷػߏ͕͋ε͹ೝ஌ෛՙ௿࣮͘૷ͱ͖δ͕ɺ࢒೦ͳ͕β 5zqf4dsjquʹ͸ͳ͍ maketagid :: string -> either validationerror tagid, ໋ྩͱ 3ftvmu const result = ok(command).asyncandthen(({ date, restaurantids }) =>, ໋ྩతʹॻ͍ͨํ͕͍͍ॴ͸खଓ͖ͱॻ͖ gspn5ispxbcmfgspn1spnjtfͱแή export const sendtask = <t>({ project, queue, location,, ΍ͬͯέͯɺ࣮ࡍͳ͏ • ैདྷͷ։ൃαγ΋ɺݎ࿚ʹͳͬͨͱࢥ͏ – ӡ༻ظؒ ೥΄ͳɻෆ۩߹ʹαδো֐͕গͳ͍ɻίʔυͷܦ೥ྼխ΋཈͑βε͍ͯδ – ୹ظతͳ։ൃεϐʔυʹ͸ྑ͘΋ѱ͘΋өڹ͸ͳ͍ ଎͘ͳͬͨɺͱ͔͸ͳ͍ 3ftvmuύζϧ͸໘౗, ΄͔ • σʔλͱ;δ·͍͸ұମխ͍ͯ͠ͳ͍ɻσʔλ͸͋͘·ͱϓϩʔϯͳσʔλɺͳͷͱϩπϡʔλ·͍ͨͩ஋ͷड͚ ౉͕͠΍γ΍͍͢ • 5zqf4dsjquʹ͸෼ׂ୅ೖ͕͋δͷͱʮ%50λհͨ͠஋ͷ٧ί௚͠ʯλҙࣝతʹॻ͔ͳͯ͘α͘ͳͬͨ • xpslgmpxͱఆ͍ٛͯ͠δܕ͸΋͏গ͠؆ૉխͱ͖δͱ͍͍͔΋ – ͪΐͬͱ৑௕ͳؾ͕͍ͯ͠δ, ·ͱί • 5zqf4dsjquʹαδ (sbqi2-όοϋτϯυ։ൃͱɺυϝπϯϩπϡʔͷ࣮૷ʹؔ਺ܕελ πϧλ༻͍͍ͯδ • ͳδ΂͘ܕͱσʔλߏ଄΍ϑϩʔλදݱ͢δ͜ͱͱɺݎ࿚ͳγεςϝʹͳͬͨ • γεςϝશମλέδͱɺઃܭ΍࣮૷͸ैདྷͱେ͖͕ࠩ͋͘δθ͚ͱ͸ͳ͍ɻԇ௕্ʹ͋δ –, ͝ࢀߟ uuu ҏલͷൃදεϥπυͳͳ • 5zqf4dsjquʹαδ (sbqi2-όοϋτϯυ։ൃ  4qfblfs%fdl – iuuqttqfblfsefdldpnobpzbuzqftdsjquojzpsvhsbqirmcbuvlvfoeplbjgbcebcbbed.

typescript tuple assignment

Modules - Theory

Scripts and modules in javascript.

In the early days of JavaScript, when the language only ran in browsers, there were no modules, but it was still possible to split the JavaScript for a web page into multiple files by using multiple script tags in HTML:

This approach had some downsides, especially as web pages grew larger and more complex. In particular, all scripts loaded onto the same page share the same scope—appropriately called the “global scope”—meaning the scripts had to be very careful not to overwrite each others’ variables and functions.

Any system that solves this problem by giving files their own scope while still providing a way to make bits of code available to other files can be called a “module system.” (It may sound obvious to say that each file in a module system is called a “module,” but the term is often used to contrast with script files, which run outside a module system, in a global scope.)

There are many module systems , and TypeScript supports emitting several , but this documentation will focus on the two most important systems today: ECMAScript modules (ESM) and CommonJS (CJS). ECMAScript Modules (ESM) is the module system built into the language, supported in modern browsers and in Node.js since v12. It uses dedicated import and export syntax: js // a.js export default "Hello from a.js" ; js // b.js import a from "./a.js" ; console . log ( a ); // 'Hello from a.js' CommonJS (CJS) is the module system that originally shipped in Node.js, before ESM was part of the language specification. It’s still supported in Node.js alongside ESM. It uses plain JavaScript objects and functions named exports and require : js // a.js exports . message = "Hello from a.js" ; js // b.js const a = require ( "./a" ); console . log ( a . message ); // 'Hello from a.js'

Accordingly, when TypeScript detects that a file is a CommonJS or ECMAScript module, it starts by assuming that file will have its own scope. Beyond that, though, the compiler’s job gets a little more complicated.

TypeScript’s job concerning modules

The TypeScript compiler’s chief goal is to prevent certain kinds of runtime errors by catching them at compile time. With or without modules involved, the compiler needs to know about the code’s intended runtime environment—what globals are available, for example. When modules are involved, there are several additional questions the compiler needs to answer in order to do its job. Let’s use a few lines of input code as an example to think about all the information needed to analyze it:

To check this file, the compiler needs to know the type of sayHello (is it a function that can accept one string argument?), which opens quite a few additional questions:

  • Will the module system load this TypeScript file directly, or will it load a JavaScript file that I (or another compiler) generate from this TypeScript file?
  • What kind of module does the module system expect to find, given the file name it will load and its location on disk?
  • If output JavaScript is being emitted, how will the module syntax present in this file be transformed in the output code?
  • Where will the module system look to find the module specified by "greetings" ? Will the lookup succeed?
  • What kind of module is the file resolved by that lookup?
  • Does the module system allow the kind of module detected in (2) to reference the kind of module detected in (5) with the syntax decided in (3)?
  • Once the "greetings" module has been analyzed, what piece of that module is bound to sayHello ?

Notice that all of these questions depend on characteristics of the host —the system that ultimately consumes the output JavaScript (or raw TypeScript, as the case may be) to direct its module loading behavior, typically either a runtime (like Node.js) or bundler (like Webpack).

The ECMAScript specification defines how ESM imports and exports link up with each other, but it doesn’t specify how the file lookup in (4), known as module resolution , happens, and it doesn’t say anything about other module systems like CommonJS. So runtimes and bundlers, especially those that want to support both ESM and CJS, have a lot of freedom to design their own rules. Consequently, the way TypeScript should answer the questions above can vary dramatically depending on where the code is intended to run. There’s no single right answer, so the compiler must be told the rules through configuration options.

The other key idea to keep in mind is that TypeScript almost always thinks about these questions in terms of its output JavaScript files, not its input TypeScript (or JavaScript!) files. Today, some runtimes and bundlers support loading TypeScript files directly, and in those cases, it doesn’t make sense to think about separate input and output files. Most of this document discusses cases where TypeScript files are compiled to JavaScript files, which in turn are loaded by the runtime module system. Examining these cases is essential for building an understanding of the compiler’s options and behavior—it’s easier to start there and simplify when thinking about esbuild, Bun, and other TypeScript-first runtimes and bundlers . So for now, we can summarize TypeScript’s job when it comes to modules in terms of output files:

Understand the rules of the host enough

  • to compile files into a valid output module format ,
  • to ensure that imports in those outputs will resolve successfully , and
  • to know what type to assign to imported names .

Who is the host?

Before we move on, it’s worth making sure we’re on the same page about the term host , because it will come up frequently. We defined it before as “the system that ultimately consumes the output code to direct its module loading behavior.” In other words, it’s the system outside of TypeScript that TypeScript’s module analysis tries to model:

  • When the output code (whether produced by tsc or a third-party transpiler) is run directly in a runtime like Node.js, the runtime is the host.
  • When there is no “output code” because a runtime consumes TypeScript files directly, the runtime is still the host.
  • When a bundler consumes TypeScript inputs or outputs and produces a bundle, the bundler is the host, because it looked at the original set of imports/requires, looked up what files they referenced, and produced a new file or set of files where the original imports and requires are erased or transformed beyond recognition. (That bundle itself might comprise modules, and the runtime that runs it will be its host, but TypeScript doesn’t know about anything that happens post-bundler.)
  • If another transpiler, optimizer, or formatter runs on TypeScript’s outputs, it’s not a host that TypeScript cares about, as long as it leaves the imports and exports it sees alone.
  • When loading modules in a web browser, the behaviors TypeScript needs to model are actually split between the web server and the module system running in the browser. The browser’s JavaScript engine (or a script-based module-loading framework like RequireJS) controls what module formats are accepted, while the web server decides what file to send when one module triggers a request to load another.
  • The TypeScript compiler itself is not a host, because it does not provide any behavior related to modules beyond trying to model other hosts.

The module output format

In any project, the first question about modules we need to answer is what kinds of modules the host expects, so TypeScript can set its output format for each file to match. Sometimes, the host only supports one kind of module—ESM in the browser, or CJS in Node.js v11 and earlier, for example. Node.js v12 and later accepts both CJS and ES modules, but uses file extensions and package.json files to determine what format each file should be, and throws an error if the file’s contents don’t match the expected format.

The module compiler option provides this information to the compiler. Its primary purpose is to control the module format of any JavaScript that gets emitted during compilation, but it also serves to inform the compiler about how the module kind of each file should be detected, how different module kinds are allowed to import each other, and whether features like import.meta and top-level await are available. So, even if a TypeScript project is using noEmit , choosing the right setting for module still matters. As we established earlier, the compiler needs an accurate understanding of the module system so it can type check (and provide IntelliSense for) imports. See Choosing compiler options for guidance on choosing the right module setting for your project.

The available module settings are

  • node16 : Reflects the module system of Node.js v16+, which supports ES modules and CJS modules side-by-side with particular interoperability and detection rules.
  • nodenext : Currently identical to node16 , but will be a moving target reflecting the latest Node.js versions as Node.js’s module system evolves.
  • es2015 : Reflects the ES2015 language specification for JavaScript modules (the version that first introduced import and export to the language).
  • es2020 : Adds support for import.meta and export * as ns from "mod" to es2015 .
  • es2022 : Adds support for top-level await to es2020 .
  • esnext : Currently identical to es2022 , but will be a moving target reflecting the latest ECMAScript specifications, as well as module-related Stage 3+ proposals that are expected to be included in upcoming specification versions.
  • commonjs , system , amd , and umd : Each emits everything in the module system named, and assumes everything can be successfully imported into that module system. These are no longer recommended for new projects and will not be covered in detail by this documentation.
Node.js’s rules for module format detection and interoperability make it incorrect to specify module as esnext or commonjs for projects that run in Node.js, even if all files emitted by tsc are ESM or CJS, respectively. The only correct module settings for projects that intend to run in Node.js are node16 and nodenext . While the emitted JavaScript for an all-ESM Node.js project might look identical between compilations using esnext and nodenext , the type checking can differ. See the reference section on nodenext for more details.

Module format detection

Node.js understands both ES modules and CJS modules, but the format of each file is determined by its file extension and the type field of the first package.json file found in a search of the file’s directory and all ancestor directories:

  • .mjs and .cjs files are always interpreted as ES modules and CJS modules, respectively.
  • .js files are interpreted as ES modules if the nearest package.json file contains a type field with the value "module" . If there is no package.json file, or if the type field is missing or has any other value, .js files are interpreted as CJS modules.

If a file is determined to be an ES module by these rules, Node.js will not inject the CommonJS module and require objects into the file’s scope during evaluation, so a file that tries to use them will cause a crash. Conversely, if a file is determined to be a CJS module, import and export declarations in the file will cause a syntax error crash.

When the module compiler option is set to node16 or nodenext , TypeScript applies this same algorithm to the project’s input files to determine the module kind of each corresponding output file. Let’s look at how module formats are detected in an example project that uses --module nodenext :

When the input file extension is .mts or .cts , TypeScript knows to treat that file as an ES module or CJS module, respectively, because Node.js will treat the output .mjs file as an ES module or the output .cjs file as a CJS module. When the input file extension is .ts , TypeScript has to consult the nearest package.json file to determine the module format, because this is what Node.js will do when it encounters the output .js file. (Notice that the same rules apply to the .d.cts and .d.ts declaration files in the pkg dependency: though they will not produce an output file as part of this compilation, the presence of a .d.ts file implies the existence of a corresponding .js file—perhaps created when the author of the pkg library ran tsc on an input .ts file of their own—which Node.js must interpret as an ES module, due to its .js extension and the presence of the "type": "module" field in /node_modules/pkg/package.json . Declaration files are covered in more detail in a later section .)

The detected module format of input files is used by TypeScript to ensure it emits the output syntax that Node.js expects in each output file. If TypeScript were to emit /example.js with import and export statements in it, Node.js would crash when parsing the file. If TypeScript were to emit /main.mjs with require calls, Node.js would crash during evaluation. Beyond emit, the module format is also used to determine rules for type checking and module resolution, which we’ll discuss in the following sections.

It’s worth mentioning again that TypeScript’s behavior in --module node16 and --module nodenext is entirely motivated by Node.js’s behavior. Since TypeScript’s goal is to catch potential runtime errors at compile time, it needs a very accurate model of what will happen at runtime. This fairly complex set of rules for module kind detection is necessary for checking code that will run in Node.js, but may be overly strict or just incorrect if applied to non-Node.js hosts.

Input module syntax

It’s important to note that the input module syntax seen in input source files is somewhat decoupled from the output module syntax emitted to JS files. That is, a file with an ESM import:

might be emitted in ESM format exactly as-is, or might be emitted as CommonJS:

depending on the module compiler option (and any applicable module format detection rules, if the module option supports more than one kind of module). In general, this means that looking at the contents of an input file isn’t enough to determine whether it’s an ES module or a CJS module.

Today, most TypeScript files are authored using ESM syntax ( import and export statements) regardless of the output format. This is largely a legacy of the long road ESM has taken to widespread support. ECMAScript modules were standardized in 2015, were supported in most browsers by 2017, and landed in Node.js v12 in 2019. During much of this window, it was clear that ESM was the future of JavaScript modules, but very few runtimes could consume it. Tools like Babel made it possible for JavaScript to be authored in ESM and downleveled to another module format that could be used in Node.js or browsers. TypeScript followed suit, adding support for ES module syntax and softly discouraging the use of the original CommonJS-inspired import fs = require("fs") syntax in the 1.5 release . The upside of this “author ESM, output anything” strategy was that TypeScript could use standard JavaScript syntax, making the authoring experience familiar to newcomers, and (theoretically) making it easy for projects to start targeting ESM outputs in the future. There are three significant downsides, which became fully apparent only after ESM and CJS modules were allowed to coexist and interoperate in Node.js: Early assumptions about how ESM/CJS interoperability would work in Node.js turned out to be wrong, and today, interoperability rules differ between Node.js and bundlers. Consequently, the configuration space for modules in TypeScript is large. When the syntax in input files all looks like ESM, it’s easy for an author or code reviewer to lose track of what kind of module a file is at runtime. And because of Node.js’s interoperability rules, what kind of module each file is became very important. When input files are written in ESM, the syntax in type declaration outputs ( .d.ts files) looks like ESM too. But because the corresponding JavaScript files could have been emitted in any module format, TypeScript can’t tell what kind of module a file is just by looking at the contents of its type declarations. And again, because of the nature of ESM/CJS interoperability, TypeScript has to know what kind of module everything is in order to provide correct types and prevent imports that will crash. In TypeScript 5.0, a new compiler option called verbatimModuleSyntax was introduced to help TypeScript authors know exactly how their import and export statements will be emitted. When enabled, the flag requires imports and exports in input files to be written in the form that will undergo the least amount of transformation before emit. So if a file will be emitted as ESM, imports and exports must be written in ESM syntax; if a file will be emitted as CJS, it must be written in the CommonJS-inspired TypeScript syntax ( import fs = require("fs") and export = {} ). This setting is particularly recommended for Node.js projects that use mostly ESM, but have a select few CJS files. It is not recommended for projects that currently target CJS, but may want to target ESM in the future.

ESM and CJS interoperability

Can an ES module import a CommonJS module? If so, does a default import link to exports or exports.default ? Can a CommonJS module require an ES module? CommonJS isn’t part of the ECMAScript specification, so runtimes, bundlers, and transpilers have been free to make up their own answers to these questions since ESM was standardized in 2015, and as such no standard set of interoperability rules exist. Today, most runtimes and bundlers broadly fall into one of three categories:

  • ESM-only. Some runtimes, like browser engines, only support what’s actually a part of the language: ECMAScript Modules.
  • Bundler-like. Before any major JavaScript engine could run ES modules, Babel allowed developers to write them by transpiling them to CommonJS. The way these ESM-transpiled-to-CJS files interacted with hand-written-CJS files implied a set of permissive interoperability rules that have become the de facto standard for bundlers and transpilers.
  • Node.js. In Node.js, CommonJS modules cannot load ES modules synchronously (with require ); they can only load them asynchronously with dynamic import() calls. ES modules can default-import CJS modules, which always binds to exports . (This means that a default import of a Babel-like CJS output with __esModule behaves differently between Node.js and some bundlers.)

TypeScript needs to know which of these rule sets to assume in order to provide correct types on (particularly default ) imports and to error on imports that will crash at runtime. When the module compiler option is set to node16 or nodenext , Node.js’s rules are enforced. All other module settings, combined with the esModuleInterop option, result in bundler-like interop in TypeScript. (While using --module esnext does prevent you from writing CommonJS modules, it does not prevent you from importing them as dependencies. There’s currently no TypeScript setting that can guard against an ES module importing a CommonJS module, as would be appropriate for direct-to-browser code.)

Module specifiers are not transformed

While the module compiler option can transform imports and exports in input files to different module formats in output files, the module specifier (the string from which you import , or pass to require ) is always emitted as-written. For example, an input like:

might be emitted as either:

depending on the module compiler option, but the module specifier will always be "./math.mjs" . There is no compiler option that enables transforming, substituting, or rewriting module specifiers. Consequently, module specifiers must be written in a way that works for the code’s target runtime or bundler, and it’s TypeScript’s job to understand those output -relative specifiers. The process of finding the file referenced by a module specifier is called module resolution .

Module resolution

Let’s return to our first example and review what we’ve learned about it so far:

So far, we’ve discussed how the host’s module system and TypeScript’s module compiler option might impact this code. We know that the input syntax looks like ESM, but the output format depends on the module compiler option, potentially the file extension, and package.json "type" field. We also know that what sayHello gets bound to, and even whether the import is even allowed, may vary depending on the module kinds of this file and the target file. But we haven’t yet discussed how to find the target file.

Module resolution is host-defined

While the ECMAScript specification defines how to parse and interpret import and export statements, it leaves module resolution up to the host. If you’re creating a hot new JavaScript runtime, you’re free to create a module resolution scheme like:

and still claim to implement “standards-compliant ESM.” Needless to say, TypeScript would have no idea what types to assign to monkey , cow , and lion without built-in knowledge of this runtime’s module resolution algorithm. Just as module informs the compiler about the host’s expected module format, moduleResolution , along with a few customization options, specify the algorithm the host uses to resolve module specifiers to files. This also clarifies why TypeScript doesn’t modify import specifiers during emit: the relationship between an import specifier and a file on disk (if one even exists) is host-defined, and TypeScript is not a host.

The available moduleResolution options are:

  • classic : TypeScript’s oldest module resolution mode, this is unfortunately the default when module is set to anything other than commonjs , node16 , or nodenext . It was probably made to provide best-effort resolution for a wide range of RequireJS configurations. It should not be used for new projects (or even old projects that don’t use RequireJS or another AMD module loader), and is scheduled for deprecation in TypeScript 6.0.
  • node10 : Formerly known as node , this is the unfortunate default when module is set to commonjs . It’s a pretty good model of Node.js versions older than v12, and sometimes it’s a passable approximation of how most bundlers do module resolution. It supports looking up packages from node_modules , loading directory index.js files, and omitting .js extensions in relative module specifiers. Because Node.js v12 introduced different module resolution rules for ES modules, though, it’s a very bad model of modern versions of Node.js. It should not be used for new projects.
  • node16 : This is the counterpart of --module node16 and is set by default with that module setting. Node.js v12 and later support both ESM and CJS, each of which uses its own module resolution algorithm. In Node.js, module specifiers in import statements and dynamic import() calls are not allowed to omit file extensions or /index.js suffixes, while module specifiers in require calls are. This module resolution mode understands and enforces this restriction where necessary, as determined by the module format detection rules instated by --module node16 . (For node16 and nodenext , module and moduleResolution go hand-in-hand: setting one to node16 or nodenext while setting the other to something else has unsupported behavior and may be an error in the future.)
  • nodenext : Currently identical to node16 , this is the counterpart of --module nodenext and is set by default with that module setting. It’s intended to be a forward-looking mode that will support new Node.js module resolution features as they’re added.
  • bundler : Node.js v12 introduced some new module resolution features for importing npm packages—the "exports" and "imports" fields of package.json —and many bundlers adopted those features without also adopting the stricter rules for ESM imports. This module resolution mode provides a base algorithm for code targeting a bundler. It supports package.json "exports" and "imports" by default, but can be configured to ignore them. It requires setting module to esnext .

TypeScript imitates the host’s module resolution, but with types

Remember the three components of TypeScript’s job concerning modules?

  • Compile files into a valid output module format
  • Ensure that imports in those outputs will resolve successfully
  • Know what type to assign to imported names .

Module resolution is needed to accomplish last two. But when we spend most of our time working in input files, it can be easy to forget about (2)—that a key component of module resolution is validating that the imports or require calls in the output files, containing the same module specifiers as the input files , will actually work at runtime. Let’s look at a new example with multiple files:

When we see the import from "./math" , it might be tempting to think, “This is how one TypeScript file refers to another. The compiler follows this (extensionless) path in order to assign a type to add .”

This isn’t entirely wrong, but the reality is deeper. The resolution of "./math" (and subsequently, the type of add ) need to reflect the reality of what happens at runtime to the output files. A more robust way to think about this process would look like this:

This model makes it clear that for TypeScript, module resolution is mostly a matter of accurately modeling the host’s module resolution algorithm between output files, with a little bit of remapping applied to find type information. Let’s look at another example that appears unintuitive through the lens of the simple model, but makes perfect sense with the robust model:

Node.js ESM import declarations use a strict module resolution algorithm that requires relative paths to include file extensions. When we only think about input files, it’s a little strange that "./math.mjs" seems to resolve to math.mts . Since we’re using an outDir to put compiled outputs in a different directory, math.mjs doesn’t even exist next to main.mts ! Why should this resolve? With our new mental model, it’s no problem:

Understanding this mental model may not immediately eliminate the strangeness of seeing output file extensions in input files, and it’s natural to think in terms of shortcuts: "./math.mjs" refers to the input file math.mts . I have to write the output extension, but the compiler knows to look for .mts when I write .mjs . This shortcut is even how the compiler works internally, but the more robust mental model explains why module resolution in TypeScript works this way: given the constraint that the module specifier in the output file will be the same as the module specifier in the input file, this is the only process that accomplishes our two goals of validating output files and assigning types.

The role of declaration files

In the previous example, we saw the “remapping” part of module resolution working between input and output files. But what happens when we import library code? Even if the library was written in TypeScript, it may not have published its source code. If we can’t rely on mapping the library’s JavaScript files back to a TypeScript file, we can verify that our import works at runtime, but how do we accomplish our second goal of assigning types?

This is where declaration files ( .d.ts , .d.mts , etc.) come into play. The best way to understand how declaration files are interpreted is to understand where they come from. When you run tsc --declaration on an input file, you get one output JavaScript file and one output declaration file:

Because of this relationship, the compiler assumes that wherever it sees a declaration file, there is a corresponding JavaScript file that is perfectly described by the type information in the declaration file. For performance reasons, in every module resolution mode, the compiler always looks for TypeScript and declaration files first, and if it finds one, it doesn’t continue looking for the corresponding JavaScript file. If it finds a TypeScript input file, it knows a JavaScript file will exist after compilation, and if it finds a declaration file, it knows a compilation (perhaps someone else’s) already happened and created a JavaScript file at the same time as the declaration file.

The declaration file tells the compiler not only that a JavaScript file exists, but also what its name and extension are:

The last row expresses that non-JS files can be typed with the allowArbitraryExtensions compiler option to support cases where the module system supports importing non-JS files as JavaScript objects. For example, a file named styles.css can be represented by a declaration file named styles.d.css.ts .

“But wait! Plenty of declaration files are written by hand, not generated by tsc . Ever heard of DefinitelyTyped?” you might object. And it’s true—hand-writing declaration files, or even moving/copying/renaming them to represent outputs of an external build tool, is a dangerous, error-prone venture. DefinitelyTyped contributors and authors of typed libraries not using tsc to generate both JavaScript and declaration files should ensure that every JavaScript file has a sibling declaration file with the same name and matching extension. Breaking from this structure can lead to false-positive TypeScript errors for end users. The npm package @arethetypeswrong/cli can help catch and explain these errors before they’re published.

Module resolution for bundlers, TypeScript runtimes, and Node.js loaders

So far, we’ve really emphasized the distinction between input files and output files . Recall that when specifying a file extension on a relative module specifier, TypeScript typically makes you use the output file extension :

This restriction applies since TypeScript won’t rewrite the extension to .js , and if "./math.ts" appears in an output JS file, that import won’t resolve to another JS file at runtime. TypeScript really wants to prevent you from generating an unsafe output JS file. But what if there is no output JS file? What if you’re in one of these situations:

  • You’re bundling this code, the bundler is configured to transpile TypeScript files in-memory, and it will eventually consume and erase all the imports you’ve written to produce a bundle.
  • You’re running this code directly in a TypeScript runtime like Deno or Bun.
  • You’re using ts-node , tsx , or another transpiling loader for Node.

In these cases, you can turn on noEmit (or emitDeclarationOnly ) and allowImportingTsExtensions to disable emitting unsafe JavaScript files and silence the error on .ts -extensioned imports.

With or without allowImportingTsExtensions , it’s still important to pick the most appropriate moduleResolution setting for the module resolution host. For bundlers and the Bun runtime, it’s bundler . These module resolvers were inspired by Node.js, but didn’t adopt the strict ESM resolution algorithm that disables extension searching that Node.js applies to imports. The bundler module resolution setting reflects this, enabling package.json "exports" support like node16 and nodenext , while always allowing extensionless imports. See Choosing compiler options for more guidance.

Module resolution for libraries

When compiling an app, you choose the moduleResolution option for a TypeScript project based on who the module resolution host is. When compiling a library, you don’t know where the output code will run, but you’d like it to run in as many places as possible. Using "module": "nodenext" (along with the implied "moduleResolution": "nodenext" ) is the best bet for maximizing the compatibility of the output JavaScript’s module specifiers, since it will force you to comply with Node.js’s stricter rules for import module resolution. Let’s look at what would happen if a library were to compile with "moduleResolution": "bundler" (or worse, "node10" ):

Assuming ./utils.ts (or ./utils/index.ts ) exists, a bundler would be fine with this code, so "moduleResolution": "bundler" doesn’t complain. Compiled with "module": "esnext" , the output JavaScript for this export statement will look exactly the same as the input. If that JavaScript were published to npm, it would be usable by projects that use a bundler, but it would cause an error when run in Node.js:

On the other hand, if we had written:

This would produce output that works both in Node.js and in bundlers.

In short, "moduleResolution": "bundler" is infectious, allowing code that only works in bundlers to be produced. Likewise, "moduleResolution": "nodenext" is only checking that the output works in Node.js, but in most cases, module code that works in Node.js will work in other runtimes and in bundlers.

Of course, this guidance can only apply in cases where the library ships outputs from tsc . If the library is being bundled before shipping, "moduleResolution": "bundler" may be acceptable. Any build tool that changes the module format or module specifiers to produce the final build of the library bears the responsibility of ensuring the safety and compatibility of the product’s module code, and tsc can no longer contribute to that task, since it can’t know what module code will exist at runtime.

Nightly Builds

How to use a nightly build of TypeScript

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

Andrew Branch  (6)

Last updated: May 08, 2024  

COMMENTS

  1. TypeScript Tuples

    To learn more about access modifiers like readonly go to our section on them here: TypeScript Classes. If you have ever used React before you have worked with tuples more than likely. useState returns a tuple of the value and a setter function. const [firstName, setFirstName] = useState('Dylan') is a common example.

  2. TypeScript: Playground Example

    TypeScript has special analysis around arrays which contain multiple types, and where the order in which they are indexed is important. These are called tuples. Think of them as a way to connect some data, but with less syntax than keyed objects.

  3. TypeScript: Documentation

    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() {.

  4. Tuples in TypeScript: A Complete Guide

    Creating tuples in TypeScript is straightforward. Here's how you can declare and initialize a tuple. let employee: [number, string, boolean]; employee = [1, 'Alice', true]; This tuple specifies that the first element is a number, the second is a string, and the third is a boolean. The sequence in which you declare the types is how TypeScript ...

  5. TypeScript Tuple Type Explained By Examples

    The types of elements are known, and need not be the same. For example, you can use a tuple to represent a value as a pair of a string and a number: let skill: [ string, number ]; skill = [ 'Programming', 5 ]; Code language: TypeScript (typescript) The order of values in a tuple is important. If you change the order of values of the skill tuple ...

  6. Exploring use cases for TypeScript tuples

    The major difference between arrays and tuples is that when we assign values to a tuple, these values must match the types defined in the tuple declaration in the same order. On the other hand, ... TypeScript tuples are like arrays with a fixed number of elements. They provide us with a fixed-size container that can store values of multiple ...

  7. TypeScript

    TypeScript - Tuples. TypeScript introduced a new data type called Tuple. Tuple can contain two values of different data types. Consider the following example of number, string and tuple type variables. var empName: string = "Steve"; // Tuple type variable var employee: [number, string] = [1, "Steve"]; In the above example, we have defined a ...

  8. Using tuples

    Assign the variable to value ... Typescript tuples are a convenient way of strongly-typing small and obvious data structures. It is essential to use a type annotation with these rather than rely on type inference. Further information about the tuple type can be found in the TypeScript handbook.

  9. TypeScript Tuples

    user [2] = "John"; // valid user [3] = 4; // valid user [4] = true; // invalid.. In the above code, because the tuple was declared with a number and a string, we can input an element of either the string or number in no order provided they aren't the first two elements. We still can't assign a boolean value to an element because the tuple wasn't declared with a boolean type.

  10. Tuples

    Definite Assignment. Object and Unknown Types. The never Type and switch Statements. Object Spread. Tuples. Functions. ... Introduction to tuples in TypeScript. Tuples are a method of defining a type that has a finite number of unnamed properties, with each property having an associated type. When using a tuple, all of the properties must be ...

  11. TypeScript Tuples Tutorial

    TypeScript Tuples Tutorial. ... In the example above, we assign the values of the tuple into separate variables. Summary: Points to remember A tuple is a data container that can store multiple values of different types. We use [] (square brackets) to initialize a tuple with values separated by a comma.

  12. TypeScript: Playground Example

    Named Tuples. Tuples are arrays where the order is important to the type system, you can learn more about them in example:tuples In TypeScript 4.0, the type of a Tuple's gained the ability to give a name to the different parts of the array. For example, you used to write a Lat Long location via a tuple: type OldLocation = [number, number] const ...

  13. Assignments

    Assignments. TypeScript narrowing using assignments is a way to narrow the type of a variable based on the value assigned to it. When a variable is assigned a value, TypeScript infers its type based on the assigned value, and it narrows the type of the variable to match the inferred type. let value: string | number; value = "hello";

  14. JavaScript variable assignments from tuples

    Please note that Tuple isn't used as a normal constructor. The solution doesn't rely on the prototype system at all, but solely on higher order functions. What are the advantages of tuples over Arrays used like tuples? Church encoded tuples are immutable by design and thus prevent side effects caused by mutations.

  15. TypeScript Tuples

    Tuples may be one or more than one types of data (like number with string or string with number and so on). To denote a multi-dimensional coordinate system the term used is tuple in abstract mathematics. In JavaScript we doesn't have tuples as data types, but in typescript Tuples facility is available. Syntax.

  16. Narrowing Function Parameters With Rests And Tuples

    TypeScript is smart enough that when elements of a tuple are narrowed, other elements of that same tuple are narrowed too. That's why TypeScript knows that if fruit is an "apple" inside logFruitTuple, it can narrow the type of info to AppleInfo. You can isolate that smartness separately from function parameters.

  17. TypeScript: Documentation

    That's why in TypeScript 4.0, tuples types can now provide labels. type Range = [start: number, end: number]; To deepen the connection between parameter lists and tuple types, the syntax for rest elements and optional elements mirrors the syntax for parameter lists.

  18. Named Tuple Type (Labeled)

    Named Tuple Type (Labeled) Tuple types can include optional labels or names for each element. These labels are for readability and tooling assistance, and do not affect the operations you can perform with them. type T = string; type Tuple1 = [T, T]; type Tuple2 = [a: T, b: T]; type Tuple3 = [a: T, T]; // Named Tuple plus Anonymous Tuple.

  19. TypeScript: Documentation

    Cannot assign to 'resident' because it is a read-only property. 2540 Cannot assign to 'resident' because it is a read-only property. ... Why might optional and rest elements be useful? Well, it allows TypeScript to correspond tuples with parameter lists. Tuples types can be used in rest parameters and arguments, so that the following: ts.

  20. How to use a tuple in a class in TypeScript

    I'm trying to learn TypeScript (2.1) by creating a dice roller. I figured I'd use tuples to match up the side rolled with a picture. For example, if I roll a 1 (using a random number generator I plan on implementing), I get back the representation for a circle. class D6 { values: [number, string]; values = [1, "Circle"]; }

  21. TypeScript 関数型スタイルでバックエンド開発のリアル

    TypeScript 関数型スタイルでバックエンド開発のリアル Search. Naoya Ito May 10, 2024 Programming 24 6.5k ... (input.sortOrder) const values = Result.combine(tuple(tagId, groupId, label, icon, sortOrder)) return values.map(([id, groupId, label, icon, sortOrder]) => ({ ...input, id, groupId, label, icon, sortOrder ...

  22. TypeScript: Handbook

    Array. TypeScript, like JavaScript, allows you to work with arrays of values. Array types can be written in one of two ways. In the first, you use the type of the elements followed by [] to denote an array of that element type: let list: number[] = [1, 2, 3]; The second way uses a generic array type, Array<elemType>:

  23. typescript union type judgment is not intuitive

    When you index access the tuple UU (=["Kars", "Esidisi"]) in Has2 with T[number] you get an union type "Kars" | "Esidisi".. Usually, when dealing with unions assignment is only valid if the type you want to assign has fewer union members than the target type. When conditional types act on a generic type, they become distributive which is what happens here. ...

  24. TypeScript: Documentation

    How TypeScript models JavaScript modules. When the input file extension is .mts or .cts, TypeScript knows to treat that file as an ES module or CJS module, respectively, because Node.js will treat the output .mjs file as an ES module or the output .cjs file as a CJS module. When the input file extension is .ts, TypeScript has to consult the nearest package.json file to determine the module ...