A brief discussion on the understanding of TypeScript index signatures

A brief discussion on the understanding of TypeScript index signatures

We use two objects to describe the salaries of two coders:

const salary1 = {
  baseSalary: 100_000,
  yearlyBonus: 20_000
};
 
const salary2 = {
  contractSalary: 110_000
};


Then write a function to get the total salary

function totalSalary(salaryObject: ???) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000


If it were you, how would you declare the salaryObject parameter of totalSalary() function to accept an object with string keys and numeric values?

The answer is to use an index signature!

Next, let’s look at what TypeScript index signatures are and when they are needed.

1. What is an index signature?

The idea of ​​index signatures is to type objects whose structure is unknown when only the key and value types are known.

It fits perfectly in the case of salary parameter, as the function should accept salary objects of different structures, the only requirement being that the attribute values ​​are numbers.

We declare salaryObject parameter with an index signature

function totalSalary(salaryObject: { [key: string]: number }) {
  let total = 0;
  for (const name in salaryObject) {
    total += salaryObject[name];
  }
  return total;
}
 
totalSalary(salary1); // => 120_000
totalSalary(salary2); // => 110_000


{[key: string]: number} is the index signature, which tells TypeScript salaryObject must be an object with string as key and number as value.

2. Index signature syntax

The syntax for index signatures is fairly straightforward and looks similar to the syntax for properties, but there is one difference. We just write the key type inside square brackets instead of the property name: { [ key: KeyType]: ValueType }.

Below are some examples of index signatures.

string type is the key and value.

interface StringByString {
  [key: string]: string;
}
 
const heroesInBooks: StringByString = {
  'Gunslinger': 'Front-end Wisdom',
  'Jack Torrance': 'Wang Dazhi'
};


The string type is the key, and the value can be string , number or boolean

interface Options {
  [key: string]: string | number | boolean;
  timeout: number;
}
 
const options: Options = {
  timeout: 1000,
  timeoutMessage: 'The request timed out!',
  isFileUpload: false
};

The signature key can only be a string `, number or symbol `. Other types are not allowed.

3. Notes on index signatures

There are some caveats with index signatures in TypeScript that you need to be aware of.

3.1 Non-existent properties

What happens if you try to access a non-existent property of an object with an index signature of { [key: string]: string }?

As expected, TypeScript infers the type of the value to be string . But checking the runtime value, it is undefined :

According to TypeScript , the value variable is of type string , but its runtime value is undefined .

An index signature simply maps a key type to a value type, nothing more. If this mapping is not done correctly, the value type may deviate from the actual runtime data type.

To make the input more accurate, the index value is marked as string or undefined . This way, TypeScript will realize that the property you are accessing may not exist.

3.2 string and number keys

Suppose there is a dictionary of number names:

interface NumbersNames {
  [key: string]: string
}
 
const names: NumbersNames = {
  '1': 'one',
  '2': 'two',
  '3': 'three',
  // ...
};

No, it works normally.

JavaScript implicitly coerces numbers to strings when used as keys in property accessors ( names[1] is the same as names['1' ]). TypeScript also enforces this.

You can think of [key: string ] as the same as [key: string | number] .

4. Index signature vs. Record<Keys, Type>

TypeScript has a utility type Record<Keys, Type>, is similar to index signatures.

const object1: Record<string, string> = { prop: 'Value' }; // OK
const object2: { [key: string]: string } = { prop: 'Value' }; // OK

So the question is... when do you use Record<Keys, Type>, when do you use index signatures? At first glance, they look similar

As we know, index signatures only accept string , number or symbol as key types. It is an error if you try to use, for example, a union of string literal type as a key in an index signature.

Index signatures are generic with respect to the keys.

But we can use a union of string literals to describe the keys in Record<keys, Type>

type Salary = Record<'yearlySalary'|'yearlyBonus', number>
 
const salary1: Salary = { 
  'yearlySalary': 120_000,
  'yearlyBonus': 10_000
}; // OK


Record<Keys, Type> is for key-specific issues.

It is recommended to annotate generic objects with index signatures, e.g. the key is of type string. However, when you know the keys in advance, use Record<Keys, Type> to annotate specific objects, such as string literals ' prop1' | 'prop2' being used for the keys.

Summarize:

If you don't know the object structure you're dealing with, but you know the possible key and value types, then index signatures are what you need.

An index signature consists of the index name and its type in square brackets, followed by a colon and the value type: { [indexName: KeyType]: ValueType }, KeyType can be a string , number , or symbol , and ValueType can be any type.

This concludes this article on the understanding of TypeScript index signatures. For more related TypeScript index signature content, please search 123WORDPRESS.COM's previous articles or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Detailed steps to build the TypeScript environment and deploy it to VSCode
  • A tutorial on how to install, use, and automatically compile TypeScript
  • Debug static pages with typescript in .net6 using vs2022

<<:  Mysql implements regular clearing of old data in a table and retaining several pieces of data (recommended)

>>:  Solve the problem that Docker cannot ping the host machine under Mac

Recommend

Using JavaScript in HTML

The <script> tag In HTML5, script has the f...

How to upgrade CentOS7 to CentOS8 (detailed steps)

This article uses a specific example to introduce...

JS implements jQuery's append function

Table of contents Show Me The Code Test the effec...

Global call implementation of Vue2.x Picker on mobile terminal

Table of contents What is the Picker component Pr...

MySql 8.0.11-Winxp64 (free installation version) configuration tutorial

1. Unzip the zip package to the installation dire...

Detailed explanation of vue.js dynamic components

:is dynamic component Use v-bind:is="compone...

Modularity in Node.js, npm package manager explained

Table of contents The basic concept of modularity...

Docker uses a single image to map to multiple ports

need: The official website's resource server ...

Detailed example of MySQL joint table update data

1.MySQL UPDATE JOIN syntax In MySQL, you can use ...

MySQL partitioning practice through Navicat

MySQL partitioning is helpful for managing very l...

A brief summary of basic web page performance optimization rules

Some optimization rules for browser web pages Pag...

Nginx's practical method for solving cross-domain problems

Separate the front and back ends and use nginx to...

Practice of Vue global custom instruction Modal drag

Table of contents background Implementation ideas...

Two methods to disable form controls in HTML: readonly and disabled

In the process of making web pages, we often use f...