简体   繁体   中英

How can I use TypeScript Generics for a function that can return either objects or arrays?

Similar to Object is of type 'unknown' typescript generics but that question doesn't specify return types in the question.

I have some existing working JS code that uses the classic JSON.parse(JSON.stringify()) technique to clone objects.

When I first turned it into TS, I used Record<string, unknown> to specify it would return an object with a string key and unknown value.

const deepClone = (
  object: Record<string, unknown> 
): Record<string, unknown> => {
  return JSON.parse(JSON.stringify(object));
};

This works fine. But I then realised the function needed to both accept and return arrays to, so I added:

const deepClone = (
  object: Record<string, unknown> | Array<unknown>
): Record<string, unknown> | Array<unknown> => {
  return JSON.parse(JSON.stringify(object));
};

But this fails testing:

  describe(`deepClone`, () => {
    it(`Deep clones object`, () => {
      const names = ["frank"];
      const original = { names };
      const clone = deepClone(original);
      names.push("nancy");
      expect(clone.names).toEqual(["frank"]);
    });
  });
      Property 'names' does not exist on type 'unknown[]'.

I understand the error - arrays can't have a property 'names' even though objects can.

This calls for generics! So following the generics documentation

const deepClone = <Type>(
  object: Record<string, unknown> | Array<unknown>
): Type => {
  return JSON.parse(JSON.stringify(object));
};

However this still fails with:

error TS2571: Object is of type 'unknown'.

How can I use TypeScript Generics for a function that can return either objects or arrays?

Maybe I'm missing something, but I think it's just a matter of defining a generic type T and using T for the function argument as well as the return value:

const deepClone = <T extends Record<string, unknown> | Array<unknown>>
  (object: T): T => {
  
  return JSON.parse(JSON.stringify(object));
};

const o = deepClone({a: 1});
const a = deepClone(['a', 1]); 

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