1

Here is the function that simplifies the formatting of console outputs:

function generateConsoleMethodParametersForFormattedOutput(
    formattedOutputData: Array<[string, { [CSS_Key: string]: string; }]>
): Array<string> {

    const outputContents: Array<string> = [];
    const CSS_DeclarationsForEachContent: Array<string> = [];

    for (const singleFormattedOutputData of formattedOutputData) {

        outputContents.push(`%c${singleFormattedOutputData[0]}`);

        let CSS_Declarations: string = "";

        for (const [ CSS_Key, CSS_Value ] of Object.entries(singleFormattedOutputData[1])) {
        CSS_Declarations = `${CSS_Declarations}${CSS_Key}: ${CSS_Value};`;
        }

        CSS_DeclarationsForEachContent.push(CSS_Declarations);
    }

    return [ outputContents.join(""), ...CSS_DeclarationsForEachContent ];
}

Now we can make the formatting output as:

console.log(...generateConsoleMethodParametersForFormattedOutput([
    [ " Red bold ", { background: "red", color: "white", "font-weight": "bold", "border-radius": "4px" } ],
    [ " Blue italic", { color: "blue", "font-style": "italic" } ]
]));

What if we want to add the conditional element in generateConsoleMethodParametersForFormattedOutput([])? The basic approach is:

[  "RequiredElement", condition ? [ "ConditionlaElement" ] : [] ]

Here, we have the TypeScript error:

console.log(...generateConsoleMethodParametersForFormattedOutput([
    [ " Red bold ", { background: "red", color: "white", "font-weight": "bold", "border-radius": "4px" } ],
    [ " Blue italic", { color: "blue", "font-style": "italic" } ],
    ...mockCondition ? [ [ " Teal ", { color: "teal" } ] ] : []
]));
Type '(string | { color: string; })[]' is not assignable to type '[string, { [CSS_Key: string]: string; }]'.
  Target requires 2 element(s) but source may have fewer.(2322)

But the compiled JavaScript works:

enter image description here

My mistake or TypeScrirpt bug?

🌎 Fiddle

5
  • Also: this is legit a function I would use, please make this into a library! Commented Apr 9, 2021 at 3:55
  • @LoganDevine, the library is exists, but the documenting of it will take a lot of time. This function available as printFormattedErrorLogToConsole protected static method of AbstractFrontEndLogger class of [email protected]. (The usage is import {AbstractFrontEndLogger} from hikari-es-extensions/BrowserJS). Sorry for not available yet documentation... Commented Apr 9, 2021 at 4:05
  • @LoganDevine, sorry for keep you waiting. This functionality has been realized and documented, but the library has been renamed to @yamato-daiwa/es-extensions. I am very sorry if you don't need it anymore. Commented Jul 9, 2021 at 23:13
  • TYSM for that! I'll use it in my next project. Commented Jul 9, 2021 at 23:35
  • @LoganDevine, I am glad about it will help you. Please feel free to open the issues. I also will try to apply for the creating of @yamato-daiwa/es-extensions tag in StackOverflow because I have not enough reputation to create it myself. But if it will be created I'll watch for the new questions with this badge and answer to it. Commented Jul 10, 2021 at 0:51

1 Answer 1

2

Problem

In the expression ...mockCondition ? [ [ " Teal ", { color: "teal" } ] ] : [], the type inferred for the result of the ternary condition will be (string | { color: string; })[] (a generic, infinite array) instead of [string, { [CSS_Key: string]: string; }] (the tuple type). This is because the expression is not calculated at compile time, so it's resultant type can/doest not be "matched" with function's parameters' types.

Solution

Use type assertion.

type OutputData = Array<[string, { [CSS_Key: string]: string; }]>
// ^^^^^ declare type here

function generateConsoleMethodParametersForFormattedOutput(
    formattedOutputData: OutputData
): Array<string> {

    const outputContents: Array<string> = [];
    const CSS_DeclarationsForEachContent: Array<string> = [];

    for (const singleFormattedOutputData of formattedOutputData) {

        outputContents.push(`%c${singleFormattedOutputData[0]}`);

        let CSS_Declarations: string = "";

        for (const [ CSS_Key, CSS_Value ] of Object.entries(singleFormattedOutputData[1])) {
        CSS_Declarations = `${CSS_Declarations}${CSS_Key}: ${CSS_Value};`;
        }

        CSS_DeclarationsForEachContent.push(CSS_Declarations);
    }

    return [ outputContents.join(""), ...CSS_DeclarationsForEachContent ];
}


declare const mockCondition: boolean


console.log(...generateConsoleMethodParametersForFormattedOutput([
    [ " Red bold ", { background: "red", color: "white", "font-weight": "bold", "border-radius": "4px" } ],
    [ " Blue italic", { color: "blue", "font-style": "italic" } ],
    ...(mockCondition ? [ [ " Teal ", { color: "teal" } ] ] : []) as OutputData // type asssertion
]));

Playground

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the solution and explanations!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.