4

EDIT: Link to a MRE (thanks @Thomas)

I have these types :

export declare type Matrix2D = [
  number, number,
  number, number,
  number, number,
];

export declare type Matrix3D = [
  number, number, number, number,
  number, number, number, number,
  number, number, number, number,
  number, number, number, number,
];

export declare type Matrix = Matrix2D | Matrix3D;

export type Coords2D = [number, number]
export type Coords3D = [number, number, number]
export type Coords4D = [number, number, number, number]
export type Coords = Coords2D | Coords3D | Coords4D

...And this code :

export function translate(...x:[Coords]|number[]):Matrix{
  if(typeof(x[0]) == "number") {
    return [ // Transposed
      1    , 0    , 0    , 0    ,
      0    , 1    , 0    , 0    ,
      0    , 0    , 1    , 0    ,
      x[0] , x[1]??0 , x[2]??0 , x[3]??1 ,
//           ^^^^^^^   ^^^^^^^   ^^^^^^^    ERROR
    ]
  }
  else {
    const X = normalize(x[0])
    return [ // Transposed
      1    , 0    , 0    , 0    ,
      0    , 1    , 0    , 0    ,
      0    , 0    , 1    , 0    ,
      X[0] , X[1] , X[2] , X[3] ,
    ]
  }
}

The error is this one :

error TS2322: Type 'number | Coords' is not assignable to type 'number | undefined'.
  Type 'Coords2D' is not assignable to type 'number'.

       x[0] , x[1]??0 , x[2]??0 , x[3]??1 ,
              ~~~~~~~

If I am not mistaking, when I use [Coords]|number[] as the type of the rest parameter, I telling TS that the rest parameter is either a tuple containing a single value of type Coords, which is itself a tuple (thus an array) and not a number. Either an array of number ?

Why is the compiler complaining about the second value (x[1]) telling me "Type 'number | Coords' is not assignable to type 'number | undefined'" while it can't even be a Coord ?

hl037_
  • 3,520
  • 1
  • 27
  • 58
  • I assume the return type of `M.Matrix` is supposed to just be `Matrix`? – T.J. Crowder Jun 07 '22 at 10:42
  • 1
    Yes, it's because it's an imported module, and I pasted here as it was. I'll edit – hl037_ Jun 07 '22 at 10:44
  • I don't understand, how is TypeScript supposed to know you didn't do `translate(42)`? `typeof x[0]` would be `number`, but `x[1]` would be `undefined`, and `Matrix` isn't allowed to contain `undefined`. – T.J. Crowder Jun 07 '22 at 10:44
  • `translate(42)` is "allowed" and `x[1]` would be `undefined` and that was even weirder because Matrix is not supposed to allow undefined (but the error tell it accept it). By the way adding `??0` as I just edited to each of these values raise the same error – hl037_ Jun 07 '22 at 10:53
  • 1
    You might be interested in https://github.com/microsoft/TypeScript/issues/49185 although it's marked as duplicate. – snak Jun 07 '22 at 11:00
  • First of all, I'm not sure if it is intentional or not:`...x:[Coords]|number[]`. It means that `x` is an array of arrays. Maybe it worth using `(...x: Coords)` ? If you change it , all errors will gone. Second, you can use generic utility type for creating tuples. See [this](https://tsplay.dev/NdA3ym) example. I think it worth creating separate function for each type of coordinate and then write some typeguards. Let me know if it works for you – captain-yossarian from Ukraine Jun 07 '22 at 11:19
  • 2
    [More minimal example](https://www.typescriptlang.org/play?#code/KYDwDg9gTgLgBAMwK4DsDGMCWEVxlAQxQGcAbAmYACgDo6QAuOAbWZSQFsAjYKAXT5wAPnHbdezPgEomYnlDgBvAFBw4mBHCowAnmGAQEVEMwAM0uAF5LcAERzetqUtVq4UYDCRRcJgIx8ANyuAL5wwKTEwC5u7p7euKbBaiHKIUA) on TS Playground. – Thomas Jun 07 '22 at 11:27
  • @captain-yossarianfromUkraine It is intended to be an array of number (either you pass each coordinates as arguments, either you pass a vector). The work around is to use type assertions, but I was surprised ts can't narrow the type in this situation, but as pointed out in the github issue, it's a known problem... – hl037_ Jun 07 '22 at 11:44

0 Answers0