Describe un arreglo profundamente anidado en TypeScript
¿Cómo defino un tipo o interfaz que describa un arreglo profundamente anidado en TypeScript?
Por ejemplo, digamos que estoy escribiendo una función para probar un camino contra cualquier número de patrones.
function match(path: string, matcher: Matcher): boolean { /* ... */ }
El tipo Matcher puede ser cualquiera de los siguientes:
stringRegExpMatcher[](nota la autorreferencia)
En otras palabras, el compilador debería aceptar lo siguiente:
match('src/index.js', 'lib/**/*');
match('src/index.js', /\/node_modules\//);
match('src/index.js', ['src/**/*', /\.js$/]);
match('src/index.js', ['src/**/*', [/\.js$/, ['*.ts']]]);
Pero lo siguiente debería producir un error de compilación:
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!!!
¿Hay alguna manera de lograr esto en TypeScript?
Respuesta #1
Sí, puedes hacer esto en TypeScript. La solución es un poco extensa, pero se puede hacer usando una combinación de alias de tipos genéricos e interfaces.
Comienza con una interfaz que defina un arreglo profundamente anidado.
interface DeepArray<T> extends Array<T | DeepArray<T>> { }
Hasta ahora, el compilador aceptará lo siguiente:
type Matcher = DeepArray<string | RegExp>;
const m1: Matcher = ['src/**/*', /\.js$/];
const m2: Matcher = ['src/**/*', [/\.js$/, ['*.ts']]];
Pero la pregunta especifica que la función también debería aceptar un solo string o RegExp. Esto todavía producirá un error del compilador.
const m3: Matcher = 'lib/**/*'; // Compiler Error!!!
const m4: Matcher = /\/node_modules\//; // Compiler Error!!!
Podemos resolver este problema con un alias de tipo genérico:
type Deep<T> = T | DeepArray<T>;
Y ahora nuestro tipo funciona como se esperaba.
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!!!
