Реагирует на машинописный тип возвращаемого объекта Object.assign - PullRequest
2 голосов
/ 14 января 2020

У меня есть этот небольшой пользовательский хук, который возвращает результат Object.assign. В документации говорится, что это возвращает массив, но приведенный ниже пример можно использовать с деструктуризацией массива И деструктуризацией объекта.

Код:

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;

Этот код можно использовать следующими способами :

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

Как это работает? Почему я могу деструктурировать как массив и объект?

Во-вторых: Как напечатать это в Typescript? Типы данных:

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

1 Ответ

4 голосов
/ 14 января 2020

Вы можете использовать деструктурирование в квадратных скобках на любом объекте с итератором, включая, в частности, массивы.

Вы можете использовать деструктурирование в фигурных скобках на любом объекте (а массивы являются объектами ).

Когда вы делаете

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

Вы создаете массив, который имеет оба нормальных значения массива [0], [1], но также имеет свойства .data, .setData и др. c. Это довольно странно в Javascript, но поскольку массивы являются объектами, и поскольку объектам могут быть назначены произвольные пары ключ-значение, это допустимо.

Таким образом, вы можете извлечь свойства из объекта, используя [ деструктурирование, вызов итератора массива, или с использованием { деструктурирование, извлечение именованных свойств из объекта.

Тем не менее, это не то, что вы следует сделать, потому что (как показывает ваш вопрос), немного запутывает происходящее , и читаемость, вероятно, является наиболее важным фактором для кода. В массивах почти никогда не должно быть произвольных пар ключ-значение (за исключением случая совпадения регулярного выражения, когда дополнительные свойства генерируются самим интерпретатором).

Чтобы ввести его, используйте обобщенные значения для введите initialValue, чтобы его можно было передать useState, и объявите массив as const, чтобы при деструктуризации массива были получены правильные типы в правильном порядке:

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 })
};
...