class Animal<T extends string> {
eat(food: T): void {
console.log('eating ' food)
}
}
class Rabbit extends Animal<'carrot'> {}
class Cat extends Animal<'mouse'>{}
type MyPet = Rabbit | Cat
const myPets: Record<string, MyPet> = {
'aa': new Rabbit(),
'bb': new Cat()
}
function getPets (name: string): MyPet {
return myPets[name]
}
const pet = getPets('aa')
// error: Argument of type 'string' is not assignable to parameter of type 'never'.
pet.eat('carrot')
pet.eat('mouse')
Please check the source code [source code replication], The generic method is called by using the joint type of two subclasses. The parameter type is inferred as never
. Shouldn't it be carrot | mouse
。
CodePudding user response:
The problem is that your code doesn't allow TS to work properly by being not precise enough with some of the type definitions. This code works as expected:
class Animal<T extends string> {
eat(food: T): void {
console.log('eating ' food)
}
}
class Rabbit extends Animal<'carrot'> {}
class Cat extends Animal<'mouse'>{}
type MyPet = Rabbit | Cat
const myPets = {
'aa': new Rabbit(),
'bb': new Cat()
}
function getPets <T extends keyof typeof myPets>(name: T): typeof myPets[T] {
return myPets[name]
}
const pet = getPets('aa')
pet.eat('carrot')
pet.eat('mouse') // error: Argument of type '"mouse"' is not assignable to parameter of type '"carrot"'
See here
In your original code you were using
const myPets: Record<string, MyPet> = {
'aa': new Rabbit(),
'bb': new Cat()
}
So TS will lose the information that myPets.aa
is a Rabbit
. It will trat myPets.aa
as type MyPet
. And since the types 'mouse'
and 'carrot'
have nothing in common, you cannot feed that pet
.
CodePudding user response:
class Animal<T extends string> {
eat(food: T): void {
console.log('eating ' food)
}
}
class Rabbit extends Animal<'carrot'> {}
class Cat extends Animal<'mouse'>{}
// type MyPet = Rabbit | Cat
const myPets = {
'aa': new Rabbit(),
'bb': new Cat()
}
function getPets <T extends keyof typeof myPets>(name: T): typeof myPets[T] {
return myPets[name]
}
// Neme is not sure
const name = 'aa' as keyof typeof myPets
const pet = getPets(name)
// error: Argument of type 'string' is not assignable to parameter of type 'never'.
pet.eat('carrot')
pet.eat('mouse')
See here