区分阶级联合

时间:2019-05-09 21:31:13

标签: typescript union discriminated-union

使用打字稿3.4我试图基于位于每个子类上的单个只读字段(区分符)来区分打字稿类的并集。本身似乎很简单,但我似乎无法解决它。

下面是一个到游乐场的链接,其中createFruit方法应能够采用通用参数来由鉴别器过滤下一个属性。任何见解将不胜感激;但是,它似乎允许评估永远不会。

abstract class Fruit {
    abstract readonly fruitType: string;
}

class Banana extends Fruit {
    fruitType = 'banana';
    length = 2;
    color = 'yellow';
}

class Pear extends Fruit {
    fruitType = 'pear';
    roundness = 'very round';
}

class Apple extends Fruit {
    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>) => { }

createFruit('pear', {} ) // Argument of type '{}' is not assignable to parameter of type 'never'.

TS Playground

1 个答案:

答案 0 :(得分:0)

问题是派生类中的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: ""
})