Search code examples
c#javascriptienumerabletypescript

Implementing IEnumerable in JavaScript / TypeScript


I'm trying to implement the C# keyword yield with in JavaScript/TypeScript (doesn't matter which): For example, I would like to implement the code:

//using System.Collections;  
//using System.Diagnostics; 
public static void Process()
{
    // Display powers of 2 up to the exponent of 8:  
    foreach (int number in Power(2, 8))
    {
        Debug.Write(number.ToString() + " ");
    }
    // Output: 2 4 8 16 32 64 128 256
}


public static IEnumerable Power(int baseNumber, int highExponent)
{
    int result = 1;

    for (int counter = 1; counter <= highExponent; counter++)
    {
        result = result * baseNumber;
        yield return result;
    }
}

in JavaScript.

The end goal is to implement a function written in C# from another question I asked about on stackoverflow, in JavaScript:

public static IEnumerable<string> SplitByCharacterType(string input)
{
    if (String.IsNullOrEmpty(input))
        throw new ArgumentNullException(nameof(input));

    StringBuilder segment = new StringBuilder();
    segment.Append(input[0]);
    var current = Char.GetUnicodeCategory(input[0]);

    for (int i = 1; i < input.Length; i++)
    {
        var next = Char.GetUnicodeCategory(input[i]);
        if (next == current)
        {
            segment.Append(input[i]);
        }
        else
        {
            yield return segment.ToString();
            segment.Clear();
            segment.Append(input[i]);
            current = next;
        }
    }
    yield return segment.ToString();
}

Any ideas?


Solution

  • I don't think there's a reasonable way to make this work in the context of a for loop that preserves the C# semantics of lazy evaluation during the "move next" operation. You can simulate this reasonably with closures, though.

    (TypeScript code):

    function getPowers(base: number, maxExponent: number) {
        var currentExponent = 1;
        return function() {
            if(currentExponent > maxExponent) {
                return undefined;
            } else {
                return Math.pow(base, currentExponent++);
            }
        }
    }
    
    // Simple test
    var p = getPowers(2, 8);
    var n: number;
    while((n = p()) !== undefined) {
        console.log(n);
    }
    
    // Demonstrate that multiple instances work
    var p2 = getPowers(2, 3);
    var p3 = getPowers(3, 3);
    while(true) {
        var n2 = p2();
        var n3 = p3();
        if((n2 || n3) === undefined) break;
    
        console.log(n2 + ", " + n3);
    }