定义映射的记录类型,其中Record <T,K>中的每个K取决于T的值?

时间:2019-06-24 18:15:18

标签: typescript

这是我三周前问到的这个问题的延伸:Set the keys of an interface to the possible values of a different interface?

简短的版本是我具有以下类型定义

interface SuccessStatus {
  type: 'success';
  payload: string;
}

interface LoadingStatus {
  type: 'loading';
} 

interface ErrorStatus {
  type: 'error';
  error: string;
}

type RequestStatus = SuccessStatus | LoadingStatus | ErrorStatus;

以及以下映射的记录类型,以为每个上述状态定义一个具有“处理程序”的对象:

type RequestHandlerVisitor = Record<
  RequestStatus["type"], 
  (status: RequestStatus) => void
>;

每个T都有一个K函数。

这将定义一个看起来像这样的对象:

const statusVisitor: RequestHandlerVisitor = {
  "success": (status: RequestStatus) => { ... },
  "loading": (status: RequestStatus) => { ... },
  "error": (status: RequestStatus) => { ... },
}

现在,我要定义的是一个类似的类型,其中K的值根据哪个键是T而变化,因此它看起来像这样:

const statusVisitor: NewRequestHandlerVisitor = {
  "success": (status: SuccessStatus) => { ... },
  "loading": (status: LoadingStatus) => { ... },
  "error": (status: ErrorStatus) => { ... },
}

在这种情况下,函数K的第一个参数的值根据T的不同而变化。

一种选择是像这样硬编码该类型:

interface NewRequestHandlerVisitor {
  "success": (status: SuccessStatus) => void;
  "loading": (status: LoadingStatus) => void;
  "error": (status: ErrorStatus) => void;
}

在这种特定情况下可以满足我的需求,但是当我有更多的“状态”类型时就变得笨拙,每种类型都需要使用该类型的新条目。

有没有办法动态定义类似的东西?

谢谢!

1 个答案:

答案 0 :(得分:2)

您可以使用自定义映射类型和Extract条件类型来完成此操作:

interface SuccessStatus {
  type: 'success';
  payload: string;
}

interface LoadingStatus {
  type: 'loading';
} 

interface ErrorStatus {
  type: 'error';
  error: string;
}

type RequestStatus = SuccessStatus | LoadingStatus | ErrorStatus;

type RequestHandlerVisitor = {
  [P in RequestStatus["type"]]: (s: Extract<RequestStatus, { type: P }>) => void
}