I seem to have a understanding problem of how typescript types works. I have the following situation. I have a class which provides a function which can be overriden:
/**
* The current log method. Can be overridden to redirect output.
*/
log: (...args: any[]) => void;
I have the following type
type AzureTransport = {
(...args: any[]): void
}
No I have a kind of facade which looks like:
export interface DataChampLogger {
info(...args: any[]): void
error(...args: any[]): void
warn(...args: any[]): void
verbose(...args: any[]): void
setLogLevel(level: DataChampLogLevel): void
setTransport<T>(transport: T): void
// implementation
class .... {
setTransport<AzureTransport>(transport: AzureTransport): void {
AzureLogger.log = transport
}
}
}
this does not work, I get the following error Type 'AzureTransport' is not assignable to type '(...args: any[]) => void'.ts(2322)
when I refactor the code to:
export interface DataChampLogger {
info(...args: any[]): void
error(...args: any[]): void
warn(...args: any[]): void
verbose(...args: any[]): void
setLogLevel(level: DataChampLogLevel): void
setTransport(transport: unknown): void
// implementation
class .... {
setTransport(transport: AzureTransport): void {
AzureLogger.log = transport
}
}
}
everything works fine, but it is not really clear to why I get an error in the first version of the implementation.
[edit] Playground Link
Thanks for your time and help
Regards Mathias
CodePudding user response:
It's because Typescript cannot know that the AzureTransport
type that you use in the class will be assignable to T
, since T
could be something else.
You can add a generic constraint like that:
export interface DataChampLogger {
setTransport<T extends AzureTransport>(transport: T): void; // "T extends AzureTransport" is the constraint
}
class MyClass implements DataChampLogger {
setTransport(transport: AzureTransport): void {
}
}
Alternatively, you can move the generic to the interface itself, like that:
export interface DataChampLogger<T> // generic is here {
setTransport(transport: T): void;
}
class MyClass implements DataChampLogger<AzureTransport> {
setTransport(transport: AzureTransport): void { // no complaints since T is AzureTransport
}
}
On a side note, this
type AzureTransport = {
(...args: any[]): void
}
is the same as
type AzureTransport = (...args: any[]) => void;
You don't need the curly brackets.