Sorry if the title is not accurate, It's kind of a weird question.
I have the following code:
enum LogType {
file = "file",
http = "http",
database = "database"
}
interface LoggerDetails {
// ... bunch of properties
provider: "datadog" | "log4j" | "newrelic"
}
interface Logger {
type: LogType;
provider: LoggerDetails["provider"];
}
interface NetworkLogger extends Logger {
type: LogType.http,
provider: "datadog"
}
interface FileLogger extends Logger {
type: LogType.file,
provider: "log4j"
}
type LoggerKey = `${LogType}.${Logger["provider"]}`;
// type LegalLoggerKeys = Extract<LoggerKey, "http.datadog" | "file.log4j">;// <-- This works, but hard coded. Also, it requires us to write it down for every new logger interface
type LegalLoggerKeys = unknown; // ??
// should only accept 'http.datadog' and 'file.log4j' as keys using the interfaces that extends Logger
const record: Record<LegalLoggerKeys, (message: string) => void> = {
}
My goal is to create LegalLoggerKeys
using the interfaces FileLogger
, NetworkLogger
, or any other implementation. as you can see my commented code, I was able to do it with hard coded string literals.
Is it possible to create the same thing using the interfaces? Playground Link
CodePudding user response:
The compiler won't be able to automatically discover all interfaces declared to extend Logger
, so you'll need to maintain such a list yourself manually. One way to do that is with a union:
type KnownLoggers = NetworkLogger | FileLogger // <-- maintain this manually
Once you have such a union, you can manipulate it to generate the union of acceptable keys. If you have a single logger type L
that extends Logger
, you can compute the allowed key via the template literal type:
type LoggerKey<L extends Logger> = `${L['type']}.${L['provider']}`;
type NetworkLoggerKey = LoggerKey<NetworkLogger>;
// type NetworkLoggerKey = "http.datadog"
But if you have a union of logger types, this won't behave the way you want, since each piece of that concatenated string will be split into unions separately:
type KnownLoggerKeys = LoggerKey<KnownLoggers>
// type KnownLoggerKeys = "file.datadog" | "file.log4j" | "http.datadog" | "http.log4j"