Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Describe a deeply nested array in TypeScript

How do I define a type or interface describing a deeply nested array in TypeScript?

For example, let's say I am writing a function for testing a path against any number of patterns.

function match(path: string, matcher: Matcher): boolean { /* ... */ }

The Matcher type may be any of the following:

  • string
  • RegExp
  • Matcher[] (note the self-reference)

In other words, the compiler should accept the following:

match('src/index.js', 'lib/**/*');
match('src/index.js', /\/node_modules\//);
match('src/index.js', ['src/**/*', /\.js$/]);
match('src/index.js', ['src/**/*', [/\.js$/, ['*.ts']]]);

But the following should produce a compiler error:

match('src/index.js', {'0': 'src/**/*'});               // Compiler Error!!!
match('src/index.js', ['src/**/*', true]);              // Compiler Error!!!
match('src/index.js', ['src/**/*', [/\.js$/, [3.14]]]); // Compiler Error!!!

Is there a way to achieve this in TypeScript?

like image 613
McMath Avatar asked Nov 15 '16 05:11

McMath


People also ask

How do you define a type of nested array in TypeScript?

You could also use a type to define a two-dimensional array. Copied! type Nested = number[][]; const arr: Nested = [ [1, 2, 3], [4, 5, 6], ]; If you have an object with a property that is a two-dimensional array, you can also use an interface.

What is a nested array?

Nested Array in JavaScript is defined as Array (Outer array) within another array (inner array). An Array can have one or more inner Arrays. These nested array (inner arrays) are under the scope of outer array means we can access these inner array elements based on outer array object name.

How do I create a nested object in TypeScript?

Use an interface or a type alias to type a nested object in TypeScript. You can set properties on the interface that point to nested objects. The type of the object can have as deeply nested properties as necessary.

Should I use [] or array in TypeScript?

There is no difference at all. Type[] is the shorthand syntax for an array of Type . Array<Type> is the generic syntax. They are completely equivalent.


1 Answers

Yes, you can do this in TypeScript. The solution is a bit verbose, but it can be done using a combination of generic type aliases and interfaces.

Start with an interface defining a deeply nested array.

interface DeepArray<T> extends Array<T | DeepArray<T>> { }

So far, the compiler will accept the following:

type Matcher = DeepArray<string | RegExp>;

const m1: Matcher = ['src/**/*', /\.js$/];
const m2: Matcher = ['src/**/*', [/\.js$/, ['*.ts']]];

But the question specifies that the function should also accept a single string or RegExp. This will still produce a compiler error.

const m3: Matcher = 'lib/**/*';         // Compiler Error!!!
const m4: Matcher = /\/node_modules\//; // Compiler Error!!!

We can solve this problem with a generic type alias:

type Deep<T> = T | DeepArray<T>;

And now our type works as expected.

type Matcher = Deep<string | RegExp>;

function match(path: string, matcher: Matcher): boolean { /* ... */ }

match('src/index.js', 'lib/**/*');
match('src/index.js', /\/node_modules\//);
match('src/index.js', ['src/**/*', /\.js$/]);
match('src/index.js', ['src/**/*', [/\.js$/, ['*.ts']]]);

match('src/index.js', {'0': 'src/**/*'});                 // Compiler Error!!!
match('src/index.js', ['src/**/*', true]);                // Compiler Error!!!
match('src/index.js', ['src/**/*', [/\.js$/, [3.14]]]);   // Compiler Error!!!
like image 105
McMath Avatar answered Oct 03 '22 22:10

McMath