简体   繁体   中英

How to extend type of Function return value Base TS generics

I have a TS problem about using generics in Function. In summary, I would like to write a function, which accepts a array of objects which has a specific interface. And in my function, I do something, and add a new property named 'children' on each item in array. How can I write TS type on this function? When I use this function, I will know the return value has the same type of input array of object, and., has children property also. I try to use generics, but not work.

Any help is greatly appreciated!!!

below is my example code.

// src array
const src = [
  { id: 3, parentId: 2 },
  { id: 2, parentId: 1 },
  { id: 1 },
  { id: 4 },
  { id: 5, parentId: 4 },
  { id: 6, parentId: 8 },
  { id: 7, parentId: 9 },
  { id: 7, parentId: 9, title : 'ssss' },
];

interface Src {
  id:number;
  parentId? : number | string;
  title? : string
}
// I use generics, but return value cant has children on each items of array
function test<T extends Src>(arr : Array<T>) :Array<T> {
  for(let i=0;i<arr.length;i++){
    // add children here
    arr[i].children = {xxxxx}
  }
  return arr;
}
let a = test(src)
// I want ts can tell me, each items in res array, has the same type of src, but also be added children property
let res = test(src)

You should really use some array utility method like map to achieve this

function test<T extends Src>(arr : Array<T>) {
  return arr.slice().map(item => ({
    ...item,
    children: { xxx: "XXX" }
  }))
}

this will add children: {xxx: "XXX} to every element and return the modified array with the correct type.

let srcWithChildren = test(src)
src[0].children // <--- Error.Property doesn't exist.
srcWithChildren[0].children // <--- OK. Typescript knows about the new property.

playground link

 const src = [ { id: 3, parentId: 2 }, { id: 2, parentId: 1 }, { id: 1 }, { id: 4 }, { id: 5, parentId: 4 }, { id: 6, parentId: 8 }, { id: 7, parentId: 9 }, { id: 7, parentId: 9, title: 'ssss' }, ]; function test(arr) { return arr.slice().map(item => ({...item, children: { xxx: "XXX" } })) } console.log(test(src))

Aside of @soffyo's answer, to adjust the return type to also contain the new property "children", you'll want to create a new type.

This could be done inline

function test<T extends Src>(arr : Array<T>) :Array<T & { children: object }> {
    for(let i=0;i<arr.length;i++){
        // add children here
        arr[i].children = {xxxxx}
    }
    return arr;
}

Or via type aliasing

type SrcWithChildren = Src & { children: object };

function test<T extends Src>(arr : Array<T>) :Array<SrcWithChildren> {
    for(let i=0;i<arr.length;i++){
        // add children here
        arr[i].children = {xxxxx}
    }
    return arr;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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