Typing rest operator object in TypeScript

Viewed 1190

I was trying to remove a property from an Object using the rest operator and could not figure out how to force a type on the new Object.

interface Ab {
  a: string;
  b: number;
}

interface Bc {
  b: number;
  c: boolean | undefined;
}

const ab: Ab = { a: 'a', b: 1};
const {a, ...bc} = {...ab, c: true};

I know that bc now has a type

{
  b: number;
  c: boolean;
}

is there a way to force bc to be explicitly of type Bc?

2 Answers

Actually it's pretty fun and tricky question :) So here is my solution:

interface Abc extends Ab, Bc {
  bc: Bc;
}

const ab: Ab = { a: 'a', b: 1};
const { a, ...bc }: Abc = { ...ab, c: true } as Abc;

Playground link

It feels like what you're trying to achieve is very particular to the case you're handling at the moment and not something that can be applied in general.

If I were to take your original example and rename some variables and types (without changing any code), I could get this:

interface Human {
  intelligenceQuotient: number;
  speed: number;
}

interface Dog {
  speed: number;
  name: boolean | undefined;
}

const david: Human = { intelligenceQuotient: 100, speed: 5};
const {intelligenceQuotient, ...bc} = {...david, name: "David"};

Your question then becomes:
If I remove the intelligenceQuotient from david and give him a name, then why doesn't he become a Dog?

A simplified version of the code in your question would be:

interface Human {
  numberOfLegs: number;
}

interface Dog {
  numberOfLegs: number;
}

interface DogWithName extends Dog {
  petName: string;
}

const dog: DogWithName = { numberOfLegs: 4, petName: "Snowy" };
const { petName, ...rest } = dog;

rest is neither Dog nor Human, it is of type { numberOfLegs: number; }.

Related