0

In .NET i can do:

var ls = new List<string>(1,2,3,3,3,4,5,6);

var x1 = ls.Single(x => x == 3); // throws exception because there are more elems of 3 defined in ls
var x2 = ls.SingleOrDefault(x => x==3) // Returns default of int (0) because there are more elems of 3 defined in ls
var x3 = ls.Single(x => x== 1) // returns 1

Single documentation:

https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.single?view=netcore-3.1

What would be the Typescript equivalent?

I'm working in the latest version of Angular.

sommmen
  • 6,570
  • 2
  • 30
  • 51
  • 1
    [`Array#find()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find) will give you a single item based on a predicate. If it nothing matches, you get `undefined`. It's basically `.First()`, since it doesn't fail with multiple matches. There is no direct equivalent for `.Single()` - you can use other libraries (some even add LINQ type methods in JS), or implement the functionality it yourself. – VLAZ Jul 09 '20 at 09:12
  • @VLAZ i see nothing baked in of the sorts. Welp if you could whip up a sample on how .Single or .SingleOrDefault would look like in .TS i would gladly accept the answer - .Ts is still foreign to me although i could make something myself i suppose. – sommmen Jul 09 '20 at 09:15
  • 1
    Related: [Angular 2 TypeScript how to find element in Array](https://stackoverflow.com/q/37969984/1497596) – DavidRR Jul 09 '20 at 17:16

2 Answers2

1

That's not a TypeScript problem, rather a EcmaScript one: there's no a Linq-y set of extensions, but you can easily write a function like this one:

const ls = [1, 2, 3, 3, 3, 4, 5, 6];

function single<T>(a: ReadonlyArray<T>, fallback?: T): T {
    if (a.length === 1) return a[0];
    if (a.length === 0 && fallback !== void 0) return fallback;
    throw new Error();
}

// *** Single-like ***

const s1 = single(ls.filter(x => x === 1));  //found one
console.log(s1);  //outputs 1

const s2 = single(ls.filter(x => x === 9));  //found none => throws
const s3 = single(ls.filter(x => x === 3));  //found many => throws

// *** SingleOrDefault-like (just add a valid fallback) ***

const s4 = single(ls.filter(x => x === 1), 0);  //found one
console.log(s4);

const s5 = single(ls.filter(x => x === 9), 0);  //found none => fallback
console.log(s5);

const s6 = single(ls.filter(x => x === 3), 0);  //found many => throws

Also have a check at the Immutable.JS library, which has no single-facility, but is very close to the Linq schema.

Mario Vernari
  • 6,649
  • 1
  • 32
  • 44
1

You will need to write such utility yourself, unfortunately. It could look something like:

const single = <T>(list: T[], predicate: (element: T) => boolean): T => {
  const index = list.findIndex(predicate);
  if (index === -1) throw new RangeError('No value found');

  const trimmedList: T[] = list.slice(index + 1);
  const nextIndex = trimmedList.findIndex(predicate);
  if (nextIndex !== -1) throw new RangeError('Multiple values found');

  return list[index];
};

const predicate = (value: number) => value === 1;

// These should then behave just like Single in .NET
single([1, 2, 3, 4], predicate); // Will return 1
single([1, 1, 2, 3, 4], predicate); // Will throw 'Multiple values found'
single([2, 3, 4], predicate); // Will throw 'No value found'
Ján Jakub Naništa
  • 1,880
  • 11
  • 12