1

I have this object:

const ABCD = {
  a: 1,
  b: 2,
  c: 3,
  d: 4
}

I can destructure it, collect the rest of it using the "spread" operator, and type the variables like this:

const {a, b, ...restOfIt}: {a: number, b: number} = ABCD;

But how do I also type the restOfIt on the same line? The following all fail:

 const {a, b, ...restOfIt}: {a: number, b: number, ...restOfIt: any} = ABCD;
 const {a, b, ...restOfIt}: {a: number, b: number, restOfIt: any} = ABCD;

TypeScript playground here

Marcus Junius Brutus
  • 26,087
  • 41
  • 189
  • 331
  • Why do you need to explicitly annotate it? TypeScript should be able to infer the types for you. – kelsny Sep 06 '22 at 13:54

1 Answers1

1

You can use dynamic key definition

const {a, b, ...restOfIt}: {a: number, b: number, [key: string]: any} = ABCD;

If you know all types in restOfIt is number, you also can use number instead of any which is better

const {a, b, ...restOfIt}: {a: number, b: number, [key: string]: number} = ABCD;

If you already have a type for restOfIt, you can use type union

type CD = {
  c: number,
  d: number
}
const {a, b, ...restOfIt}: { a: number, b: number} & CD = ABCD;

Playground

Nick Vu
  • 14,512
  • 4
  • 21
  • 31
  • This would break if `a` or `b` is not `number` – Tobias S. Sep 06 '22 at 11:55
  • This works but apparently, in the general case, it can't be made as strict / rigorous as one would want it too. E.g. suppose I had already defined a type `CD` for the `restOfIt`. How would I assert that the `restOfIt` is of type `CD` ? – Marcus Junius Brutus Sep 06 '22 at 11:57
  • @TobiasS. hmm from the question, he defined `a` and `b` as a number type – Nick Vu Sep 06 '22 at 12:00
  • 1
    @MarcusJuniusBrutus I added the part related to `CD` type as you mentioned, we can use type union in that case – Nick Vu Sep 06 '22 at 12:00
  • @NickVu quite close now but still, the above code does not really assert the type of `restOfIt` under certain cases. E.g. if I had `type CD = {a: number, c: number, d: number}`, that would still type check because the entirety of the values is compared against the entirety of the type. – Marcus Junius Brutus Sep 06 '22 at 12:19
  • `that would still type check` you mean it's invalid or valid in the above case? from the inspection of the above code snippet, we can see `restOfIt` has type `{ c: number, d: number }`. Could you add on your expectation in your question, I can try to look into it closely. @MarcusJuniusBrutus – Nick Vu Sep 06 '22 at 12:26
  • @NickVu I mean that if you defined `CD` as `type CD = {a: number, c: number, d: number}` then the code is still found to be VALID, even though `restOfIt` is `{c: number, d: number}` and NOT `{a: number, c: number, d: number}`. – Marcus Junius Brutus Sep 06 '22 at 12:49
  • a union type is to unify `{ a: number, b: number }` and `{a: number, c: number, d: number}` to become a new type which is `{ a: number b: number, c: number, d: number }` (merged `a: number` because of duplication). For `...restOfIt`, if you check `restOfIt.a`, it will be invalid because `restOfIt` only contains `c` and `d` @MarcusJuniusBrutus – Nick Vu Sep 06 '22 at 12:59