繁体   English   中英

基于对象属性的类型函数

[英]Type functions based on property in object

我正在尝试正确键入接口/对象,以便可以为具有特定类型的每个对象创建函数。 我不知道如何尝试更好地解释它,所以我会给你一些代码。

这是我的界面:

export interface Activity {
  id: string;
  metaData:
    | {
        type: "createTask";
        data: { taskId: string; taskName: string; user: string };
        task: string;
        taskName: string;
      }
    | {
        type: "deleteTask";
        data: { taskName: string; user: string };
        task: string;
        taskName: string;
      }
    | {
        type: "updateTask";
        data: { taskId: string; taskName: string; user: string };
        task: string;
        taskName: string;
      }
    | {
        type: "createScenario";
        data: {
          scenarioId: string;
          scenarioName: string;
          taskName: string;
          user: string;
        };
        task: string;
        taskName: string;
      }
    | {
        type: "updateScenario";
        data: { scenarioId: string; scenarioName: string; user: string };
        task: string;
        scenario: string;
        taskName: string;
      }
    | {
        type: "deleteScenario";
        data: { scenarioName: string; user: string };
        task: string;
        taskName: string;
      };
}

现在,我想从这个界面为每种不同类型的活动键入一个函数,以便我可以根据类型查找该函数。

这是我尝试过的:

export const activityFormatFunctions: Record<
  Activity["metaData"]["type"],
  (activity: Activity) => string
> = {
  createScenario: (activity) => {
    return ""
  },
  createTask: (activity) => {
    return ""
  },
  deleteScenario: (activity) => {
    return ""
  },
  deleteTask: (activity) => {
    return ""
  },
  updateScenario: (activity) => {
    activity.metaData.data.scenarioName;
    return ""
  },
  updateTask: (activity) => {
    activity.metaData.data.taskName;
    return ""
  },
};

问题是“活动”参数没有缩小到具有匹配类型的活动,因此我只能访问所有不同活动类型之间的公共属性。

在上面的示例中,我希望能够在updateScenario场景函数中访问scenarioName名称,因为 Activity 接口说它有一个scenarioName名称

{
  type: "updateScenario";
  data: { scenarioId: string; scenarioName: string; user: string };
  task: string;
  scenario: string;
  taskName: string;
}

链接到游乐场

为了便于阅读,我更喜欢在单独的接口中声明每个 Activity,并声明一个联合类型,以获得固定长度的可能性。

解决方案的很大一部分在于包含函数的对象的类型,并找到相应的联合类型。

type FindByType<Union, Type> = Union extends { type: Type } ? Union : never;

type MetadataMap = {
    [K in Activity<TasksUnion>["metaData"]["type"]]: (activity: Activity<FindByType<TasksUnion, K>>) => string
}

export interface Activity<T extends TasksUnion> {
  id: string;
  metaData: T
}

type TasksUnion =
 | CreateTask
 | DeleteTask
 | UpdateTask
 | CreateScenario
 | UpdateScenario
 | DeleteScenario

type TaskType =
 | "createTask"
 | "deleteTask"
 | "updateTask"
 | "createScenario"
 | "updateScenario"
 | "deleteScenario"


interface BaseTask {
    type: TaskType;
}

interface CreateTask extends BaseTask {
    type: "createTask";
    data: { taskId: string; taskName: string; user: string };
    task: string;
    taskName: string;
}

interface DeleteTask extends BaseTask {
    type: "deleteTask";
    data: { taskName: string; user: string };
    task: string;
    taskName: string;
}

interface UpdateTask extends BaseTask {
    type: "updateTask";
    data: { taskId: string; taskName: string; user: string };
    task: string;
    taskName: string;
}

interface CreateScenario extends BaseTask {
    type: "createScenario";
    data: {
        scenarioId: string;
        scenarioName: string;
        taskName: string;
        user: string;
    };
    task: string;
    taskName: string;
}


interface UpdateScenario extends BaseTask {
    type: "updateScenario";
    data: { scenarioId: string; scenarioName: string; user: string };
    task: string;
    scenario: string;
    taskName: string;
}

interface DeleteScenario extends BaseTask {
    type: "deleteScenario";
    data: { scenarioName: string; user: string };
    task: string;
    taskName: string;
};

// Everything correctly typed 👌🏻
export const activityFormatFunctions: MetadataMap = {
  createScenario: (activity) => {
    return ""
  },
  createTask: (activity) => {
    return ""
  },
  deleteScenario: (activity) => {
    return ""
  },
  deleteTask: (activity) => {
    return ""
  },
  updateScenario: (activity) => {
    activity.metaData.data.scenarioName;
    return ""
  },
  updateTask: (activity) => {
    activity.metaData.data.taskName;
    return ""
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM