Consider this class:
import type { PublishCommand, SNSClient } from '@aws-sdk/client-sns'
export class MyPublisher {
private readonly topicArn: string
private readonly snsClient: SNSClient
constructor(topicArn: string, snsClient: SNSClient) {
this.topicArn = topicArn
this.snsClient = snsClient
}
async publish(title = '', description = '', Foo: PublishCommand) {
return this.snsClient.send(
new Foo({
Message: JSON.stringify({
version: '1.0',
source: 'custom',
content: {
description,
title,
},
}),
TopicArn: this.topicArn,
}),
)
}
}
With TypeScript 5 it generates the error "This expression is not constructable." where I try to instantiate with "new Foo()". But if I add typeof just before the type of the argument Foo, it works:
import type { PublishCommand, SNSClient } from '@aws-sdk/client-sns'
export class MyPublisher {
private readonly topicArn: string
private readonly snsClient: SNSClient
constructor(topicArn: string, snsClient: SNSClient) {
this.topicArn = topicArn
this.snsClient = snsClient
}
async publish(title = '', description = '', Foo: typeof PublishCommand) {
return this.snsClient.send(
new Foo({
Message: JSON.stringify({
version: '1.0',
source: 'custom',
content: {
description,
title,
},
}),
TopicArn: this.topicArn,
}),
)
}
}
Can someone explain to me why is that? Since I’m already importing the types only. Does it even mean something to typeof a type?
2
Answers
It seem that
PublishCommand
is a class. Classes in TypeScript are a bit special, since they are both type and value at same time. TypePublishCommand
refers to instance of class, object which you get by executingnew PublishCommand()
, while valuePublishCommand
is constructor.And when you try to get type of value (by using
typeof
) you get type for constructor, not for the instance.Consider this code (playground):
Here
A
refers to type of instance of classBeep
, whileB
refers to type of constructor itself.But it’s indeed seems a bit odd, that you can use
typeof
withPublishCommand
even if you imported only type.Anything of type PublishCommand already is an object. That is to say it has already been instantiated. Your first example is like attempting to call
new 123()
ornew "Hello World"()
. If you are trying to make a new PublishCommand, you can simply callnew PublishCommand(...)
. It’s unclear what else you would be attempting to do with this code.To answer your question directly, PublishCommand, as a class (not just a type), is considered to have the type of
function
. This means that when you pass something with the same type as PublishCommand, it is also afunction
, and you can construct one with thenew
keyword