0

I have the following

sortByCounter = (ps: any) => {
    return Object.values(ps).sort(
      (a: any, b: any) => {
        return (a.Counter >= b.Counter) 
        ? -1 : 1;
      }
    );
}

Which causes typescript to say

Property 'Counter' does not exist on
type 'unknown'.

the reason why I haven't just made an interface for the object with Counter on it is because there are a lot of other possible properties on the object as well.

I have tried the LooseObject solution described in How do I dynamically assign properties to an object in TypeScript? but (replace all any with LooseObject) but it still keeps telling me that Counter does not exist on type unknown.

in fact I am as yet not using the code anywhere, just it's mere existence (which VS Code says is fine) causes typescript to crash my application.

user254694
  • 1,461
  • 2
  • 23
  • 46
  • 3
    If you're going to use code like this, I'm wondering why you'd use TypeScript at all? Better to type the function properly – CertainPerformance Nov 11 '20 at 22:19
  • 1
    Which version of typescript do You use in your package json and which version is used by VS code? Because if You copy and paste your code to typescript playground it will work fine – captain-yossarian from Ukraine Nov 11 '20 at 22:21
  • 2
    Warning - your sorting comparator is faulty. It never handles equality, so it only produces two values, for greater or lesser. Two equal values will be mistakenly considered to be "greater". This can trick the sorting algorithm and lead to subtle bugs when sorting that are very hard to find and diagnose. – VLAZ Nov 11 '20 at 22:21
  • VLAZ: I was under the impression that >= handles equality. thus const a = 1; Boolean(a > a) returns false but Boolean(a >= a) returns true – user254694 Nov 11 '20 at 22:26
  • 2
    @user254694 comparer functions are required to produce *three* values - for greater (negative), lesser (positive), and equal (zero). You are only producing two values - greater and lesser. The equality case is handled as if it's greater. Therefore, your comparator function is not symmetrical any more - `compare(a, b)` is not necessarily going to be the opposite of `compare(b, a)`. Any shortcuts the sorting algorithm may take rely on inferences made about how items sort in relation to each other to minimise the comparisons made. However, faulty comparison algorithm can throw the inference off. – VLAZ Nov 11 '20 at 22:30
  • @captain-yossarian i have "typescript": "^4.0.3" which I figured was plenty new enough. Do you know how to check which is used in VS Code, it's late here and I'm not finding anything with a quick google. – user254694 Nov 11 '20 at 22:32
  • @VLAZ ah, ok thanks. – user254694 Nov 11 '20 at 22:33
  • 1
    @user254694 open *.ts file in VS code and look on right bottom corner of VS code, You should find) – captain-yossarian from Ukraine Nov 11 '20 at 22:34
  • @captain-yossarian ok, it says 4.0.3 down there as well. Is there some typescript caching that can be going on, perhaps playing with webpack together? (I'm using webpack-dev-server and have restarted and still get error) – user254694 Nov 11 '20 at 22:39

1 Answers1

0

Calling this function only makes sense if ps is an object whose values are all objects with a property Counter. Anything else will cause a runtime error. Why not tell typescript the correct types?

const sortByCounter = (ps: Record<PropertyKey, {Counter: number}>) => {
    return Object.values(ps).sort(
      (a, b) => {
        return b.Counter - a.Counter;
      }
    );
}

The type Record<PropertyKey, {Counter: number}> says that this is an object whose keys can be any valid object keys (string | number | symbol), and whose values are objects with a number property Counter.

a and b both get properly inferred as {Counter: number}.

As explained by @VLAZ, you want a comparison to return positive negative and equal outputs, so you can just use subtraction rather than a ternary.

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
  • sometimes one doesn't know all the possible data that will be in something, but only some of the data. which is why I didn't want to tell typescript what type it was because I wasn't sure exactly all of the data that can be present in the object, only the data that I want. – user254694 Nov 12 '20 at 09:38
  • Right, so you tell typescript about the data that you want. It can include other properties and that's not a problem. We tell typescript the **minimum** that the data needs to match. If it doesn't at least have these minimum properties, it's a problem. It will be a runtime error. – Linda Paiste Nov 12 '20 at 22:17