sunknudsen
sunknudsen

Reputation: 7260

Which type should I use to match custom "HTTPError" class?

The following code (simplified for the purpose of writing this question) throws TypeScript errors and I can’t figure out why.

FYI, I am trying to set this.errorClass to a class, not an instance of a class.

class HTTPError extends Error {
  constructor(message: string) {
    super(message)
  }
}

interface HTTPOptions {
  errorClass?: HTTPError
}

class HTTP {
  errorClass: HTTPError
  constructor(options: HTTPOptions) {
    this.errorClass = options?.errorClass ? options.errorClass : HTTPError
  }
}

class TestError extends HTTPError {}
const httpInstance = new HTTP({
  errorClass: TestError,
})

Upvotes: 0

Views: 2700

Answers (2)

DoronG
DoronG

Reputation: 2663

TL;DR

Here's a solution:

class HTTPError extends Error {
  constructor(message: string) {
    super(message)
  }
}

interface HTTPOptions {
  errorClass?: typeof HTTPError
}

class HTTP {
  errorClass: typeof HTTPError
  constructor(options: HTTPOptions) {
    this.errorClass = options?.errorClass ??  HTTPError
  }
}

class TestError extends HTTPError {}
const httpInstance = new HTTP({
  errorClass: TestError,
})

The Details

The issue is that you're mixing up types and instances. You were trying to provide the class type of the error as a property, I assume, so you can do type matching and/or future instantiation, but you typed the property as an instance:

errorClass?: HTTPError // takes an instance of HTTPError, e.g. new HTTPError(...) or undefined

instead of:

errorClass?: typeof HTTPError // takes a class/factory/function which creates an instance of HTTPError, e.g. HTTPError, () => new HTTPError(), etc.

Upvotes: 3

Jay
Jay

Reputation: 3355

This seems to work for me, Disclaimer: I don't do much TypeScript.

It seems like because of the declaration of errorClass being nullable, try this:

class HTTPError extends Error {
  constructor(message: string) {
    super(message)
  }
}

interface HTTPOptions {
  errorClass?: HTTPError
}

class HTTP {
  errorClass: HTTPError
  constructor(options: HTTPOptions) {
    this.errorClass = new HTTPError(options?.errorClass?.message || '')
  }
}

class TestError extends HTTPError {}
const httpInstance = new HTTP({
  errorClass: new TestError('test'),
})

This also works:

class HTTPError extends Error {
  constructor(message: string) {
    super(message)
  }
}

interface HTTPOptions {
  errorClass: HTTPError
}

class HTTP {
  errorClass: HTTPError
  constructor(options: HTTPOptions) {
    this.errorClass = options.errorClass || HTTPError
  }
}

class TestError extends HTTPError {}
const httpInstance = new HTTP({
  errorClass: new TestError(''),
})

Upvotes: 0

Related Questions