覆盖字段类型定义
Override field type definition
我正在尝试使用 TypeScript 定义状态机并在类型级别提供一些检查。
为此,我不仅需要将配置保持在值级别,还要保持类型级别,以便能够引发编译时错误,如 "you cannot transition from a final state" 或 "the target state does not exists" 等...
让我们从状态 "type" 定义开始。
状态节点可以是 "initial"、"state" 或 "final".
类型
所以在我的配置中,我将保留一个 属性 with type 类型的字面值。 (例如,参见 EmptyStateConfig 类型)。
为了更新类型,我需要在类型级别做的是覆盖字段的类型,并将其替换为新类型。
调用 new State().type("final")
应该 return 作为类型 State<{ type: "final" }>
。
不幸的是,TS 对我大喊大叫说类型方法的 return 类型无效,因为它不满足 AnyStateConfig 类型,因为它缺少覆盖的未触及的键(但它们在那里!)。
请查看以下代码以了解更多信息:
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 with strict: true
TypeScript 不够聪明,无法推断如果 C extends AnyStateConfig
,则 Exclude<keyof C, "type">
必须包含 "states"
。看起来有 an existing issue report。我发现的解决方法是再次将 C
与 AnyStateConfig
相交:
type<StateType extends AnyStateConfig["type"]>(type: StateType): State<Override<AnyStateConfig & C, "type", StateType>>{
return new State({ ...(this.config as any), type})
}
我正在尝试使用 TypeScript 定义状态机并在类型级别提供一些检查。
为此,我不仅需要将配置保持在值级别,还要保持类型级别,以便能够引发编译时错误,如 "you cannot transition from a final state" 或 "the target state does not exists" 等...
让我们从状态 "type" 定义开始。 状态节点可以是 "initial"、"state" 或 "final".
类型所以在我的配置中,我将保留一个 属性 with type 类型的字面值。 (例如,参见 EmptyStateConfig 类型)。
为了更新类型,我需要在类型级别做的是覆盖字段的类型,并将其替换为新类型。
调用 new State().type("final")
应该 return 作为类型 State<{ type: "final" }>
。
不幸的是,TS 对我大喊大叫说类型方法的 return 类型无效,因为它不满足 AnyStateConfig 类型,因为它缺少覆盖的未触及的键(但它们在那里!)。
请查看以下代码以了解更多信息:
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 with strict: true
TypeScript 不够聪明,无法推断如果 C extends AnyStateConfig
,则 Exclude<keyof C, "type">
必须包含 "states"
。看起来有 an existing issue report。我发现的解决方法是再次将 C
与 AnyStateConfig
相交:
type<StateType extends AnyStateConfig["type"]>(type: StateType): State<Override<AnyStateConfig & C, "type", StateType>>{
return new State({ ...(this.config as any), type})
}