Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Typescript type transform

While working my way through typescript types, I have a question about transformations. I have the following type:

export type DataChampLogLevel = 'debug' | 'verbose' | 'info' | 'warning' | 'error'

No it is the case that some loggers only accept debug while others expect verbose

I have a logging facade which expects DataChampLoglevel

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

export interface DataChampLogger {

  setLogLevel(level: DataChampLogLevel): void

}

//implementation

  setLogLevel(level: DataChampLogLevel): void {
    SomeLogger.setLogLevel(level) // compiler type error debug is not allowed in type OtherLogLevel..
  }

internally I need to convert the value from e.g. debug to verbose while it is rather simple to write a convert function I was wondering if the same was possible with typesxript types e.g. String Templates or the like. I was playing around a bit but was not able to come up with the proper solution.
This is just my own curiosity to improve my skills 😉

Regards
Mathias

>Solution :

I was wondering if the same was possible with typesxript types

No. What you’re describing is a runtime value conversion. TypeScript types don’t exist at runtime (other than a small caveat around enums). So there’s no TypeScript type solution to this. You’ll need a runtime solution to modify a runtime value.

There may or may not be a type aspect to this as well, since SomeLogger.setLogLevel seems to accept a different type from DataChampLogLevel, so you’ll need a way to tell TypeScript that the (updated) value is allowed for SomeLogger.setLogLevel. But it can’t help with the runtime side of it.

For instance, let’s say that SomeLogger.setLogLevel accepts a SomeLoggerLogLevel which is:

type SomeLoggerLogLevel = 'verbose' | 'info' | 'warning' | 'error';

In that case, there’s no need to do anything explicit with the type, since TypeScript’s flow analysis can see you handling it inline if you do something like:

setLogLevel(level: DataChampLogLevel): void {
    if (level === "debug") {
        level = "verbose";
    }
    SomeLogger.setLogLevel(level);
}

But if you do it another way (like a lookup table), you may need to reassure TypeScript that your runtime conversion is correct. For instance, TypeScript won’t be happy with this:

const logLevelMap: Partial<Record<DataChampLogLevel, SomeLoggerLogLevel>> = {
    debug: "verbose",
};

const obj: DataChampLogger = {
    setLogLevel(level: DataChampLogLevel): void {
        level = logLevelMap[level] ?? level;
        SomeLogger.setLogLevel(level); // Argument of type 'DataChampLogLevel' is not assignable to parameter of type 'SomeLoggerLogLevel'.
    }
};

but if you add a type assertion function, it’s happy:

const logLevelMap: Partial<Record<DataChampLogLevel, SomeLoggerLogLevel>> = {
    debug: "verbose",
};

function assertsIsValidSomeLoggerLogLevel(level: DataChampLogLevel): asserts level is SomeLoggerLogLevel {
    if (level in logLevelMap) {
        throw new Error(`Invalid SomeLoggerLogLevel "${level}"`);
    }
}

const obj: DataChampLogger = {
    setLogLevel(level: DataChampLogLevel): void {
        level = logLevelMap[level] ?? level;
        assertsIsValidSomeLoggerLogLevel(level);
        SomeLogger.setLogLevel(level);
    }
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading