node.js - Llamada dinámica de chalk con TypeScript
Estoy usando TypeScript y quiero llamar al método chalk dinámicamente, mira mi código:
import chalk from 'chalk';
const color: string = "red";
const message: string = "My Title";
const light: boolean = false;
const colorName = `bg${capitalize(color)}${light ? 'Bright' : ''}`;
console.log(chalk[colorName](message));
Entonces, la función color toma como valor el color del fondo del mensaje. El mensaje es el contenido y light es el booleano usado para saber si se debe usar la versión brillante del fondo.
El problema es que TypeScript lanza este error:
Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'ChalkInstance'.
en la parte chalk[colorName].
Ya intenté poner (chalk[colorName] as keyof ChalkInstance). Y ya miré este post (que básicamente es el mismo problema). Obviamente, las soluciones que se dan no funcionan en mi caso.
Respuesta #1
Hay algunas cosas que necesitas hacer.
- Elimina los tipos explícitos redundantes de tus variables
color,messageylight. Hacerlo no solo es innecesario, sino que en realidad interfiere con que TypeScript infiera correctamente el valor literal de esos tipos. En otras palabras, si definesconst color="red";TypeScript sabrá, porque es unconst, que nunca cambiará y siempre puede tratarse como el literal de cadena"red"en lugar del más genéricostring. (Como regla general, nunca deberías definir explícitamente el tipo de una variableconst.)
const color = "red";
const message = "My Title";
const light = false;
- Asegúrate de que tu función
capitalize()defina correctamente su tipo de retorno. En este caso, en realidad existe un tipo de utilidad incorporado impresionanteCapitalize<>que puedes usar aquí. En combinación con un genérico de TypeScript, puedes definir la función de tal manera que TypeScript sepa que, por ejemplo, si"red"es lo que se ingresa,"Red"es lo que sale.
function capitalize<S extends string>(c: S) {
return c.replace(/\b\w/g, firstLetter => firstLetter.toUpperCase()) as Capitalize<S>;
}
- Usa la aserción
as constcuando definascolorName(y cualquier otra variable similar que necesites definir). Si no haces esto, el tipo decolorNamese inferirá comostring, lo cual no es bueno para indexarchalk. Conas const, básicamente le estás diciendo a TypeScript que trate la expresión resultante como un valor literal de cadena. En este caso, el tipo decolorNamese convierte en"bgRedBright" | "bgRed", ambos válidos como índices dechalk.
const colorName = `bg${capitalize(color)}${light ? 'Bright' : ''}` as const;
^^^^^^^^
Cuando lo pones todo junto:
import chalk from 'chalk';
const color = "red";
const message = "My Title";
const light = false;
function capitalize<S extends string>(c: S) {
return c.replace(/\b\w/g, firstLetter => firstLetter.toUpperCase()) as Capitalize<S>;
}
const colorName = `bg${capitalize(color)}${light ? 'Bright' : ''}` as const;
console.log(chalk[colorName](message));
Editar: Es posible que en el futuro necesites definir tu variable color de tal manera que sea dinámica y no solo un literal codificado "red". En ese caso, necesitas una manera de satisfacer a TypeScript de que color será siempre algo que sea válido considerando todas las demás inferencias que acabamos de configurar.
Aquí, en realidad queremos definir explícitamente un tipo para ciertas variables, particularmente let y los argumentos de las funciones. Afortunadamente, chalk proporciona un tipo muy útil para este caso, ForegroundColor, que es esencialmente todos los colores "base" válidos y resulta ser compatible con BackgroundColor cuando se usa en la forma `bg$ {ForegroundColor`, que es exactamente lo que necesitamos aquí.
import chalk, { ForegroundColor } from 'chalk';
let color: ForegroundColor = "red";
color = "blue";
Incluso podríamos mejorar nuestra función capitalize() controlando de manera más estricta cuál puede ser el tipo del argumento:
function capitalize<S extends ForegroundColor>(c: S) {
return c.replace(/\b\w/g, firstLetter => firstLetter.toUpperCase()) as Capitalize<S>;
}
Otro ejemplo de patio de juegos que pone en práctica esas mejoras adicionales.
Respuesta #2
I recommend Colors.ts for TypeScript
npm install colorts
import 'colorts/lib/string';
console.log('hello'.green); // outputs green text
console.log('i like cake and pies'.underline.red) // outputs red underlined text
console.log('inverse the color'.inverse); // inverses the color
https://github.com/shaselle/colors.ts
