8

Is there a way to add a isNullOrEmpty(str:string) to the static string object.

such that I can call it:

String.isNullOrEmpty(myobj);

I have found a way to put it on the implementation but that does not help for a method such as this.

wonea
  • 4,783
  • 17
  • 86
  • 139
maxfridbe
  • 5,872
  • 10
  • 58
  • 80

3 Answers3

16

String is defined in lib.d.ts with the following interface

interface StringConstructor {
  ...
}

declare var String: StringConstructor;

so while you can't add methods to a variable, you can add them to the interface, using

interface StringConstructor {
   isNullOrEmpty(str:string):boolean;
}

and them implement them on the variable, using

String.isNullOrEmpty = (str:string) => !str;
SWeko
  • 30,434
  • 10
  • 71
  • 106
  • Is this also possible with type Array via the ArrayConstructor? – ndee Aug 18 '16 at 14:46
  • This should work, but note that there are two interfaces, the generic `Array`, and the non-generic `ArrayConstructor`. – SWeko Aug 21 '16 at 15:29
6

TypeScript does something called declaration merging, which is explained in section 10.5 of the spec.

The gist of it is you can put members in module foo, and then later on put more members in module foo. As of 0.9 this extends to putting members in the namespace of a class as well, as long as the class is declared first. That's a new feature and I've discovered bugs around it, but it's supposed to work.

So to answer your question specifically you can just do this:

module String {
    export function isNullOrEmpty(s: string): boolean {
        return !s;
    }
}

var s: string;
alert(String.isNullOrEmpty(s).toString());    // true
s = "";
alert(String.isNullOrEmpty(s).toString());    // true
s = "asdf";
alert(String.isNullOrEmpty(s).toString());    // false

Try it out.


Apparently my answer is not complete because String is declared as a var and not a module. Declaration merging doesn't carry over to vars (as of 0.9) which is annoying. There is still a way around this though it's a bit of a hack:

// filea.ts
module String {
    export function isNullOrEmpty(s: string): boolean {
        return !!s;
    }
}
module mynamespace {
    export declare var String: {
        new (value?: any): String;
        (value?: any): string;
        prototype: String;
        fromCharCode(...codes: number[]): string;
        isNullOrEmpty(s: string): boolean;
    }
}

// fileb.ts
/// <reference path="filea.ts" />
module mynamespace {
    var s: string;
    String.isNullOrEmpty(s);    // true
    s = "";
    String.isNullOrEmpty(s);    // true
    s = "asdf";
    String.isNullOrEmpty(s);    // false
}

What's going on in filea is you're putting a function on the var String, and then declaring that mynamespace.String exists with everything String in lib.d.ts has plus what you added. Then, so long as you're working in mysnamespace, references to String will assume you're talking about mynamespace.String. That doesn't really exist so you'll get good ol' String which is what you want.

Like I said it's a bit dirty, but assuming you're following decent namespace conventions you should have a top level namespace where you only have to do this once. If you want to share the String extensions as part of a library though... well you're stuck.

Daniele Vrut
  • 2,835
  • 2
  • 22
  • 32
Jeffery Grajkowski
  • 3,982
  • 20
  • 23
  • It works on the playground as expected, however breaking it out into two ts files and referencing the string.d.ts one does not allow you to use it as expected – maxfridbe Jul 25 '13 at 14:06
  • Ah you're right. The issue there is in lib.d.ts String is declared as a var (which apparently doesn't qualify for merging) instead of a module. I don't think you can redeclare a var in the same namespace, but you can declare in a different namespace. I'll amend my answer to explain it. – Jeffery Grajkowski Jul 25 '13 at 15:35
0

My solution use different approach, because string base type in this phase cannot be extended.

module Type {
    "use strict";

    export module BaseType {
        export class ApplicationString {

            /**
             * Indicates whether the specified string is null or an Empty string.
             *
             * @property string inputString
             * @see https://msdn.microsoft.com/en-us/library/system.string.isnullorempty(v=vs.110).aspx
             */
            static isNullOrEmpty(inputString: string): boolean {
                if (inputString === null || inputString.length === 0) {
                    return true;
                } else {
                    return false;
                }
            }
        }
    }
}

alert(Type.BaseType.ApplicationString.isNullOrEmpty(null));
alert(Type.BaseType.ApplicationString.isNullOrEmpty(""));
alert(Type.BaseType.ApplicationString.isNullOrEmpty("text"));

Demo: TypeScriptPlayground

d.danailov
  • 9,594
  • 4
  • 51
  • 36