条件打字稿-转换嵌套对象/数组中的值

时间:2020-08-22 13:54:03

标签: typescript typescript-generics

我有一个函数convertStudentObjectToStudentString遍历给定的输入(因此对于对象或数组,它将遍历所有嵌套的键或元素)并将发现的任何Student实例转换为简单的字符串。

我不确定如何描述该函数的输入和输出类型。如果函数接收到一个Student,我可以立即返回一个字符串。但是,如果函数接收到对象或数组,则应返回具有相同键的相似对象/数组,除非该值恰好是Student。


class Student {
    name: string;
    constructor(name: string) {
        this.name = name;
    }
}

const alice = new Student('Alice');
const bob = new Student('Bob');

const school = {
    students: [
        alice,
        bob
    ],
    chemistryClass: {
        students: [alice]
    },
    prefect: bob,
}

function convertStudentObjectToStudentString<T>(input: T): T extends Student ? string : T {
    if (input instanceof Student) return input.name;
    if (typeof input !== 'object') return input;
    if (Array.isArray(input)) return input.map(convertStudentObjectToStudentString);
    return Object.keys(input).reduce((acc, k) => ({
        ...acc,
        [k]: convertStudentObjectToStudentString(input[k]),
    }), {});
}

console.log(school);
console.log(convertStudentObjectToStudentString(school));
// {
//   "students": ["Alice", "Bob"],
//   "chemistryClass": {
//      "students": ["Alice"]
//    },
//   "prefect": "Bob"
// }

const physicsStudents = [bob, alice];
console.log(convertStudentObjectToStudentString(physicsStudents));
// [ "Bob", "Alice" ] 

提琴:https://stackblitz.com/edit/typescript-sm5gqz

2 个答案:

答案 0 :(得分:0)

功能overloading可能适合您的情况。

Query: SEL A.JOB_ID,A.SUBJECT_AREA,A.UC4JOB AS UC4_JOB,A."WORKFLOW/JOB" AS 
 INFA_WORKFLOW,B.STATUS,A.SCH_STRT_TIME,B.START_TIME,A.SLA_TMLINE,
 '??' AS DURATION_CROSSED_AFTER_SLA
 FROM NDW_PRCS_CNTRL_VIEWS.NDW_JOB_DETAIL A JOIN 
 NDW_PRCS_CNTRL_VIEWS.NDW_JOB_RUN_STATUS B 
 ON A.REF_ID = B.REF_ID 
 AND A.JOB_ID = B.JOB_ID 
 WHERE A.REF_ID IN (4171,977,997,1428,755,898,145) 
 AND B.DATA_DATE = DATE - 1;

            
Current Output we are getting:
JOB_ID  SUBJECT_AREA    UC4_JOB INFA_WORKFLOW   STATUS  SCH_STRT_TIME   START_TIME  SLA_TMLINE  DURATION_CROSSED_AFTER_SLA
1,373   Subs by Speed   NDW.EPC.SUBS_BY_SPEED_DATA_LOAD wf_EPC_SUBS_BY_SPEED    COMPLETE    6:00 AM 8/22/2020 06:01:24  6:00 AM ??
343 CSG Run 2   NDW.P1P2MIG.NDW_CCS_DATA_EXTRACT.WF_CSG_EXTRACT_EQP_MERGE_SA    wf_CSG_EXTRACT_EQP_MERGE_SA COMPLETE    23:00 PM    8/21/2020 23:00:24  23:04 PM    ??
906 Billing NDW.P2.IN.WF_ROSETTA_SEMANTIC_ACCOUNT_LEDGER_FACT   wf_ACCOUNT_LEDGER_FACT_INC  COMPLETE    04:00 AM    8/22/2020 02:39:35  06:00 AM    ??
539 iControl    NDW.XHBU.SPRINT1.INFA_WF_DEPENDENT.ICONTROL_STG_JRNL_LOAD   wf_XH_BU_ICONTROL_dly_inc   COMPLETE    05:00 AM    8/22/2020 05:01:25  NA  ??
668 XH BB/Cell Offline  NDW.XHBU.SPRINT2.INFA_WF_DEPENDENT.BB_CELL_OFFLINE_DLY  wf_XH_BB_CELL_OFFLINE_DLY   COMPLETE    06:00 AM    8/22/2020 07:19:49  NA  ??
2,042   NDW_XHBU    NDW_XH.JOBS.SPRINT2.INFA_WF_DEPENDENT.XH_EQUIPMENT_ORDER_DLY    Wf_XH_EQUIPEMENT_ORDER_ACT_DLY  WAITING NA  ?   NA  ??

答案 1 :(得分:0)

在多玩些游戏并更多地了解自己的问题时,我在这里找到了答案:Recursive conditional types

这似乎效果很好。

type ConvertToString<T> = T extends Student ? string : {
    [K in keyof T]:
        T[K] extends (infer U)[] ? ConvertToString<U>[] :
        ConvertToString<T[K]>;
}

function convertStudentObjectToStudentString<T>(input: T): ConvertToString<T>
function convertStudentObjectToStudentString(input: any): any {
    if (input instanceof Student) return input.name;
    if (typeof input !== 'object') return input;
    if (Array.isArray(input)) return input.map(convertStudentObjectToStudentString);
    return Object.keys(input).reduce((acc, k) => ({
        ...acc,
        [k]: convertStudentObjectToStudentString(input[k]),
    }), {});
}