简体   繁体   中英

React typescript Object.assign return type

I have this small custom hook which returns an Object.assign result. In documentation it says that this returns an array, but the example below can be used with array destructuring AND object destructuring.

Code:

import { useState } from 'react';

const useStateExtended = (initialValue, initialLoading = false) => {

  const [data, setData] = useState(initialValue);
  const [loading, setLoading] = useState(initialLoading);

  return Object.assign([data, setData, loading, setLoading], { data, setData, loading, setLoading })
};

export default useStateExtended;

This code can be used in the following ways:

const {data, setData, loading, setLoading} = useStateExtended({});
const [data, setData, loading, setLoading] = useStateExtended({});

How does this work? Why can I destructure both like it is an array and an object?

Secondly: How to type this in Typescript? Data types are:

data: any;
setData: (data: any) => void;
loading: boolean;
setLoading: (boolean) => void;

You can use square-bracket destructuring on anything with an iterator, including, most notably, arrays.

You can use curly-bracket destructuring on any object (and arrays are objects).

When you do

Object.assign([data, setData, loading, setLoading], { data, setData, loading, setLoading })

You create an array which has both normal array indicies [0] , [1] , but also has properties .data , .setData , etc. This is pretty weird in Javascript, but since arrays are objects, and since objects can have arbitrary key-value pairs assigned to them, it's legal.

So, you can retrieve properties from the object either by using [ destructuring, invoking the array's iterator, or by using { destructuring, extracting the named properties from the object.

That said, this isn't something you should do, because (as your question demonstrates), it's kind of confusing what's going on, and readability is probably the most important factor for code. Arrays should pretty much never have arbitrary key-value pairs (except in the case of a regular expression match, in which case the additional properties are generated by the interpreter itself).

To type it, use generics for the type of initialValue so it can be passed to useState , and declare the array as const so that the array destructuring retrieves the right types in the right order:

const useStateExtended = <T extends unknown>(initialValue: T, initialLoading = false) => {
    const [data, setData] = useState<T>(initialValue);
    const [loading, setLoading] = useState(initialLoading);
    return Object.assign([data, setData, loading, setLoading] as const, { data, setData, loading, setLoading })
};

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