覆盖字段类型定义

时间:2018-07-31 18:22:40

标签: javascript typescript typescript-typings type-level-computation

我正在尝试使用TypeScript定义状态机,并在类型级别提供一些检查。

为此,我不仅需要将配置保持在值级别,而且还要保持类型级别,以便能够引发诸如“您无法从最终状态过渡”或“目标状态”之类的编译时错误。不存在”等...

让我们从状态“类型”定义开始。 状态节点可以是“初始”,“状态”或“最终”类型。

因此,在我的配置中,我将保留一个类型为type的文字值的属性。 (例如,参见EmptyStateConfig类型)。

为了更新类型,我需要在类型级别执行的操作是覆盖字段的类型,并用新字段替换它。

呼叫new State().type("final")的类型应为State<{ type: "final" }>

不幸的是,TS对我大喊大叫说类型方法的返回类型无效,因为它不满足AnyStateConfig类型,因为它缺少覆盖的未触键(但是它们在那里!)。 / p>

请检查以下代码以了解更多信息:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
type Override<T, K extends keyof T, V> = Omit<T, K> & { [N in K]: V }

type AnyStateConfig = {
    type: "initial" | "state" | "final"
    states: {[K: string]: AnyStateConfig}
}

type EmptyStateConfig = {
    type: "state"
    states: {}
}


class State<C extends AnyStateConfig = EmptyStateConfig>{

    constructor(
        public readonly config: C
    ){

    }

    // the following line breaks.
    type<StateType extends AnyStateConfig["type"]>(type: StateType): State<Override<C, "type", StateType>>{
        return new State({ ...(this.config as any), type})
    }
}

使用TS 2.9或3.0(严格):true

1 个答案:

答案 0 :(得分:2)

TypeScript不够聪明,无法推断出如果C extends AnyStateConfig,那么Exclude<keyof C, "type">必须包含"states"。好像有an existing issue report。我发现一种解决方法是再次将CAnyStateConfig相交:

type<StateType extends AnyStateConfig["type"]>(type: StateType): State<Override<AnyStateConfig & C, "type", StateType>>{
    return new State({ ...(this.config as any), type})
}