Проблема в том, что fruitType
в производных классах имеет тип string
, а не строковый литерал, связанный с строковым литералом. Typescript по умолчанию расширяет литеральные типы до базового типа при инициализации полей. Чтобы обойти это, вы можете использовать утверждение as const
или сделать поле w readonly
(или указать строковый литерал вручную, но это будет дублировать строку)
Решение readonly
имеет смысл, так как тип не должен меняться:
abstract class Fruit {
abstract readonly fruitType: string;
}
class Banana extends Fruit {
readonly fruitType = 'banana';
length = 2;
color = 'yellow';
}
class Pear extends Fruit {
readonly fruitType = 'pear';
roundness = 'very round';
}
class Apple extends Fruit {
readonly fruitType = 'apple';
fallOfMan = true;
hasWorms = true;
}
type KnownFruits = Banana | Pear | Apple;
type FruitTypes = KnownFruits['fruitType'];
type FruitDiscriminator<T extends FruitTypes> = Extract<KnownFruits, { fruitType: T }>;
let createFruit = <T extends FruitTypes>(fruitType: T, props: FruitDiscriminator<T>) => { }
// ok
createFruit('pear', {
fruitType: 'pear',
roundness: ""
})