skip to Main Content

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


  1. It seem that PublishCommand is a class. Classes in TypeScript are a bit special, since they are both type and value at same time. Type PublishCommand refers to instance of class, object which you get by executing new PublishCommand(), while value PublishCommand 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):

    class Beep {};
    
    type A = Beep;
    type B = typeof Beep;
    
    const a: A = new Beep();
    const b: B = Beep;
    

    Here A refers to type of instance of class Beep, while B refers to type of constructor itself.

    But it’s indeed seems a bit odd, that you can use typeof with PublishCommand even if you imported only type.

    Login or Signup to reply.
  2. 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() or new "Hello World"(). If you are trying to make a new PublishCommand, you can simply call new 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 a function, and you can construct one with the new keyword

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search