52

I have tried to create an extension method in TypeScript based on this discussion (https://github.com/Microsoft/TypeScript/issues/9), but I couldn't create a working one.

Here is my code,

namespace Mynamespace {
    interface Date {
        ConvertToDateFromTS(msg: string): Date;
    }

    Date.ConvertToDateFromTS(msg: string): Date {
        //conversion code here
    }

    export class MyClass {}
}

but its not working.

wonea
  • 4,783
  • 17
  • 86
  • 139
AhammadaliPK
  • 3,448
  • 4
  • 21
  • 39

2 Answers2

65

You need to change the prototype:

interface Date {
    ConvertToDateFromTS(msg: string): Date;
}

Date.prototype.ConvertToDateFromTS = function(msg: string): Date {
    // implement logic
}

let oldDate = new Date();
let newDate = oldDate.ConvertToDateFromTS(TS_VALUE);

Though it looks like you want to have a static factory method on the Date object, in which case you better do something like:

interface DateConstructor {
    ConvertToDateFromTS(msg: string): Date;
}

Date.ConvertToDateFromTS = function(msg: string): Date {
    // implement logic
}

let newDate = Date.ConvertToDateFromTS(TS_VALUE);
Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • 21
    throwing error, 1. property ConvertToDateFromTS is does not exist on type DateConstructor 2.property ConvertToDateFromTS is does not exist on type Date – AhammadaliPK Jul 18 '16 at 10:40
  • Where are you getting these errors? It works for me: [code in playground](https://www.typescriptlang.org/play/#src=interface%20DateConstructor%20%7B%0D%0A%20%20%20%20ConvertToDateFromTS(msg%3A%20string)%3A%20Date%3B%0D%0A%7D%0D%0A%0D%0ADate.ConvertToDateFromTS%20%3D%20function(msg%3A%20string)%3A%20Date%20%7B%0D%0A%09return%20null%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20Date%20%7B%0D%0A%20%20%20%20ConvertToDateFromTS(msg%3A%20string)%3A%20Date%3B%0D%0A%7D%0D%0A%0D%0ADate.prototype.ConvertToDateFromTS%20%3D%20function(msg%3A%20string)%3A%20Date%20%7B%0D%0A%20%20%20%20return%20null%3B%0D%0A%7D) – Nitzan Tomer Jul 18 '16 at 10:51
  • 1
    Does this have to be in the same file as the original definition of the type? Also, it didn't like this when I tried to use generics. Otherwise, great answer. Just a caveat for others (unless those can be clarified) – vbullinger Feb 28 '18 at 17:13
  • @vbullinger No, You can add to a prototype of an object which is defined elsewhere, in this example, `Date` is a built-in type, so it was defined somewhere else. As for generics, what exactly did you try do to? – Nitzan Tomer Feb 28 '18 at 19:19
  • I can't remember exactly, but I think I wanted to extend Promise. I did something else instead. – vbullinger Mar 01 '18 at 20:48
  • @vbullinger It works to do the same thing with `Promise`. If you can come up with an example then I'll be able to help more. – Nitzan Tomer Mar 01 '18 at 23:50
  • Thanks for the offer, but I went a different route and I'm happy with it, so I don't need to reinvent the solution. – vbullinger Mar 02 '18 at 22:19
  • 3
    this seems to work for existing types but not custom types – Dave Cousineau Aug 03 '20 at 21:23
  • @DaveCousineau the question and answer are both about existing types, you don't need this for custom types. – Nitzan Tomer Aug 04 '20 at 20:39
  • @NitzanTomer I have auto-generated typescript classes that I would like to manually add more things to. So far support for partial classes is refused. There must be a way to do it like this, but it doesn't seem to work. I may have to resort to having my own system that concats source files together or something. – Dave Cousineau Aug 05 '20 at 00:23
  • @DaveCousineau there's no reason why you shouldn't be able to augment your auto generated classes. i suggest that you post a new question describing your specific case. – Nitzan Tomer Aug 05 '20 at 09:10
  • 10
    For `Date`, you need to enclose the interface in `declare global { }` code block. Otherwise, the call to the prototype won't find the new method. – CesarD Apr 22 '21 at 17:58
  • How to place extension method and usage in separated files? – Jacek Sep 04 '22 at 06:09
  • what is TS_VALUE? – Hary Jun 01 '23 at 11:15
11

The previous answer gave Typescript errors

Found this to work great!

export {}

declare global {
   interface Date {
      addDays(days: number): Date;
   }
}

Date.prototype.addDays = function (days: number): Date {
   if (!days) return this;
   let date = this;
   date.setDate(date.getDate() + days);

   return date;
};

Source

Korayem
  • 12,108
  • 5
  • 69
  • 56
  • If you need to use this from Angular, then put the import statement in to the app.module.ts to make the extension available globally, and do it for the whole file, e.g. import 'path/to/my/file' – Paul F. Wood Jul 12 '23 at 14:58