Dany D
Dany D

Reputation: 1189

How to easily extend a typescript object with it's contract described by an interface

Let's say I have a CustomError interface which extends the ES6 Error one, adding a custom property.

interface CustomError extends Error {
  custom: string;
}

Now, I create a ES6 Error:

const error = new Error('something wrong');

And, in order to create the custom Error, i execute the following function:

const customError = createCustomError(error);

The createCustomError function uses Typescript's as syntax:

function createCustomError(error: Error): CustomError {
  const customError = error as CustomError;
  customError.custom = 'Custom';
  return customError;
}

This method is really easy and terse, but I am not sure it's the way to go because, it's the responsibility of this function to actually set the custom property. If it doesn't, I will have no type safety.

What do you think, should I do it like this and capture the danger through a unit test? Making sure all the CustomErrors have their custom properties set?

Or is it a better way?

This started from a frustration, because, the other way of doing this, which i know, seems to be over complicated and involves saucery.

export class BodyParserError extends Error {
  type: string;
  status: number;
  name: ErrorNames.BODY_PARSER_ERROR = ErrorNames.BODY_PARSER_ERROR;

  constructor(...args: any[]) {
    super(...args);
    this.message = args[0].message;
    this.type = args[0].type;
    this.status = args[0].status;

    Error.captureStackTrace(this, BodyParserError);
    Object.setPrototypeOf(this, BodyParserError.prototype);
  }
}

export const createBodyParserError = (error): BodyParserError => new BodyParserError(error);

Upvotes: 1

Views: 156

Answers (1)

artem
artem

Reputation: 51749

The easiest way to extend objects in TypeScript is by using Object.assign()

interface CustomError extends Error {
  custom: string;
}

const customError: CustomError = Object.assign(
    new Error('error message'), 
    { custom: 'custom message' }
);

Object.assign() is typed more or less properly in the system library, so if you for example forget to initialize or misspell some property you will get an error

const badCustomError: CustomError = Object.assign(
    new Error('error message'),
    { customm: 'custom message' }
);

// error: Property 'custom' is missing in type 'Error & { customm: string; }'

Upvotes: 1

Related Questions