基于类中的变量值的条件类型(TypeScript)

时间:2019-05-07 17:02:46

标签: typescript conditional-types

我正在创建一个名为Loadable<T>的泛型类,其中包含两个字段。一个名为state,其中包含可加载资源的当前状态。第二个名称为data,其中包含可加载资源的值。

state被定义为"loading" | "loaded" | "error",我想根据当前data的值来更改state的类型。

例如,如果state"loading",则data应该是null。我无法弄清楚这样做的语法。

我创建了一个名为type的{​​{1}},其定义为:

LoadableState<T, U>

传递的 type LoadableState<T, U> = T extends "loaded" ? U : T extends "loading" ? null : T extends "error" ? string : never; 的类型必须为T

这部分有效,但尝试以此定义"loaded" | "loading" | "error"无效。

data

TypeScript引发以下错误:export class Loadable<T> { public state: "loaded" | "loading" | "error" = "loading"; public data: LoadableState<state, T>; // ^^^^^ Cannot find name 'state` }


我尝试过的其他事情:

Cannot find name 'state'

我不确定这是否可行。如果不是,是否还有其他解决方案?

1 个答案:

答案 0 :(得分:7)

我认为没有一种方法(或至少不是一种干净的方法)使一个类属性的类型依赖于另一个属性的当前值。

最好将这两个属性组合成一个对象:

type LoadState<T> = {
    state: "loading",
} | {
    state: "loaded",
    data: T
} | {
    state: "error",
    data: string; // or maybe 'message'
}

export class Loadable<T> {
    state: LoadState<T> = { state: "loading" }
}

尽管类包装器在这里实际上不是很有用,但您可能会考虑完全不使用类。

使用此类型时,Typescript将强制您在尝试访问数据之前检查state

function handleLoadState<T>(loadState: LoadState<T>) {
   loadState.data // ERROR, can't access data, since it might not exist
   if(loadState.state === "loaded")
       loadState.data // okay
   }
}

此模式称为Discriminated Union,在Typescript中非常常用。