# C# String extensions to TypeScript prototype extensions

Microsoft [C# extension methods](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods) is a great way to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. 

# My requirements

I needed two extension methods to do the following:

* A method to convert "Yes"/"No" to it's equivalent boolean value
* A method to convert a date string to a Date object (or the minimum Date if it's a blank or malformed date string)

# My C# class

So I wrote my C# extension methods as follows:

```csharp
public static class StringExtensions {
	public static bool ToBool(this string value){
		return value.ToLower() == "yes";
	}
	
	public static DateTime ToDate(this string value){
		return DateTime.TryParse(value, out DateTime result) 
                    ? result : DateTime.MinValue;
	}	
}
```

You can see a working [.NET Fiddle](https://dotnetfiddle.net/JDPqpZ) below:

<iframe width="100%" height="475" src="https://dotnetfiddle.net/Widget/9g5Akq" frameborder="0"></iframe>


<span />

# Equivalent TypeScript extensions

So I wrote the equivalent extensions in the [TypeScript playground](https://www.typescriptlang.org/play?#code/MoFwTglgdg5gdABzAexKgnggpnNAhZZAGywEMoACAXgoDMBXKAYxAmUoAoBKCgbwFgAUBREUwWEPTCUQACwgBnXMgAyyAO5YwAYVIKs3alRoAidFgUmA3EIC+NwUNCRYiFGhCYcaACKkQWNR0jCxsnDwCwqLiktIUcooUAISmJhQA-BRQWOoUfgEc+TgIpGD6HAlKaM7QMNxcPABcWTl5-gYmAAwAjAC0AFLkvQBMnT0mXA62QkJFbqgY2Mp+6ACy7HIAmmRgQQzMrOwUhpGiYhJSMvJVqshMpCRFNbAcAORYUL0A4nivADR8IRnM4AE1I6Garyg9AAtloIEx-hQYRtZJCFLJkGAQEjzKVIdC4ZBEUDgSJbFw4OIEERSEwDAB6CgMmAA169V6TOwzQRMdgKYg4IjIOoAA14AB0TNsFFK4AAVZAEYjcWwUYCY+hEEHnWIyMD0HAUACCLHoDwoADcHobmgASXjSiwmZTKkjkVWirm8-mCuDCsWSkwAOWQcsVbtV6s12t1lzoD30cBNZot1qItooDpDyBd+EI7qgnu9fKgApI-pFHHFUu6w16AHkWCNOsNhuHkEUoxrkFqdTF43XG83Rm3k6bJGmbVh7Y6h02QC223nO+1uOlluD1lAtjtiw5S+WhVWayYO12uGqe3243E+oNPqMeuPU0QrdPZyYVxeN74t6jtlKfcgA)

```javascript
...
String.prototype.toBoolean = function () {
    return this.toLowerCase() === "yes";
};

String.prototype.toDate = function () {
    return this != "" ? new Date(Date.parse(this.toString())) : 
        new Date("01-Jan-2001");
}
...
```

Interesting, this code gives a compile time error. But still runs 😱

> Property 'toBoolean' does not exist on type 'String'.

> Property 'toDate' does not exist on type 'String'.

# How did I fix it?

I needed to declare an interface for `String` first as you can see in my [playground script](https://www.typescriptlang.org/play?ssl=17&ssc=1&pln=10&pc=1#code/JYOwLgpgTgZghgYwgAgMpiqA5sg3gWAChkTkwB7AIXPIBsI4QAKASgC5kAjG+xgbiKky5ACJxIrDmMjIAPsgCuIACYQYoCMoGEAvkSKhIsRCmkoCxUhTEBPALLlwACwCaDKJOQBnDNm17CInRMECwAOgAHKHIKMBsIiDCKajoGEGQAXmQYJQQwYEdkVjxBUigIMAUodLAnYC8k8gAZcgB3aABhOC8IYoz+5AAiGwgvQf9tIN9QyOjY+MTrcRQsnJA8gvTiiyFyyuqyOq9kAEIswcHkAH5kEAhW5DMmM0i4KB6mWvrG4OxWFhYyA4dweT0GAAYAIwAWgAUoxoQAmcFQwYsfz6QgvKIxGILRq2BzONxvTLZXL5QrbUokPZVGpHRotBBwehmX6hJgAcggIGhAHFKFyADQlSxCEjKOA2DhckAKAC20GACBFyAVjlqsq8TnIUDAapGb1l8qVmFVNIlOhYYXKEVoJiYAHpkE6sKKudCueiiAEiAhHF5UmFaOQsEwAAa4AA6gzcXljYQAKlQeKwdGhdQpaMpkHSDhgFIlkABBPIKVnIABurKLHAAJLg46NBo0UrxmCwdBGfYQAyAg-QQ2HIzHBgA5ciJlPt9OZ8jZ3P59LwWg9MKl8uVmu0OvIRsT8it5I8NLpnvafuDxKh8NR2OQxHQgDyeSR4MRiOnomWc9QWZzPMKnpZBHxfN9kU-Dcy0qbdawgBsmzA18wHfT9jx-CQWCuAlpSJWoSQ8LsL39QNg1vUdY2-J4u3nRcgP2dIYXhPlkShaCt1oat4MQi5cKwnClnsTVXHcc90SAA) and the code below:

```javascript
interface String {
    toBoolean(): boolean;
    toDate(): Date | undefined;
}

String.prototype.toBoolean = function () {
    return this.toLowerCase() === "yes";
};

String.prototype.toDate = function () {
    return this != "" ? new Date(Date.parse(this.toString())) : 
        new Date("01-Jan-2001");
}
...
```

This TypeScript code compiled and ran without any issues. Note that when you do this in your local environment, add the `interface` code to a `String.d.ts` file to keep it neat.

This [SO Answer](https://stackoverflow.com/a/53392268) helped me to write the code. 

# Why did it work?

This [SO Answer](https://stackoverflow.com/a/39877446) gives the explanation as to why adding an interface works:

> Declaring the new member so it can pass type-checking. You need to declare an interface with the same name as the constructor/class you want to modify and put it under the correct declared namespace/module. This is called scope augmentation.

