0

I'm trying to explicitly type a const which is created using a rest param in a destructured object. I can see that typescript can infer that it will have all the properties of the type of the source object, less any properties which I create separate consts for. But, I have a predefined type which I specifically want to use for my new const. Is this possible?

interface Animal {
    name: string,
    species: string,
    legs: number,
    tail: boolean,
    alive: boolean,
}

// say we know an animal is alive and therefore want a type without this property
// (yes, we could extend Animal with alive: true, but this a contrived example, go with it)
type LivingAnimal = Omit<Animal, 'alive'>

// dave is an Animal, but we want a LivingAnimal type from him, which omits the 'alive' property
const dave: Animal = {
    name: 'Dave',
    species: 'lizard',
    legs: 4,
    tail: true,
    alive: true,
}

// with object destructuring, I can infer that alive is a boolean and daveAnimal is the same type as LivingAnimal (ie has all the same props as Animal except alive)
// But what I actually *want* to achieve is to type daveAnimal specifically as LivingAnimal
const {alive, ...daveAnimal} = dave;

// but when I try and do this, it fails
const {alive2, ...daveAnimal2}: {alive2: string, ...daveAnimal2: LivingAnimal} = dave;

// so is there a way of specifying a predefined type for the animal const, created with a rest param in a destructured object?

Here is the code in the typescript playground.

I have done some googling and read articles like this one and other SO questions like this one but they don't quite cover my use of rest params, or at least not in a way which I've understood.

I hope I've explained what I'm trying to achieve adequately. It's not terribly important - in practice I can work with what I've already got, it's more for neatness and advancing my understanding. Thanks for any wisdom you can share.

sauntimo
  • 1,531
  • 1
  • 17
  • 28
  • I'm quite sure this isn't possible. Essentially `LivingAnimal` isn't a type but a type alias. – chautelly Dec 21 '20 at 18:18
  • If I created a new LivingAnimal type with the props I wanted specifically, would it then be possible? – sauntimo Dec 21 '20 at 18:19
  • It would still be the alias of an object literal – chautelly Dec 21 '20 at 18:38
  • I was with you until the "but when I try and do this, it fails" line, which I can't figure out what you want it to do (`alive2` doesn't exist and neither does `alive: string`). And on the previous line `daveAnimal` _does_ have the type of `LivingAnimal` because of typescript structural type system and can be used anywhere that a `LivingAnimal` could be used. `const foo: LivingAnimal = daveAnimal` would work fine. So can you expand on what you're asking here? What is the result you want? – Alex Wayne Dec 21 '20 at 19:55
  • @AlexWayne sorry, there was a couple of mistakes in the names on that line, which I've edited. What I was trying to do was type daveAnimal as LivingAnimal, rather than as an unamed interface with the same properties as LivingAnimal. I realise I could type another object as LivingAnimal and then set it to daveAnimal, I just wondered if I could directly type the rest param. I understand that it is functionally the same in this case. Maybe my question is pointless. – sauntimo Dec 22 '20 at 00:09
  • Can you ever type a rest param in this situation? Maybe you never really need to. – sauntimo Dec 22 '20 at 00:14
  • 1
    @sauntimo Typescript is structural, not nominal. That means that types are the same if have identical structure, but the name of that structure doesn't matter at all. So whatever problem you are trying to solve here isn't actually a problem at all. – Alex Wayne Dec 22 '20 at 18:09
  • @AlexWayne thanks, that helps! – sauntimo Dec 23 '20 at 23:20

0 Answers0