TypeScript 实用知识

818 阅读2分钟

实现 pick 方法

从一个对象中,选择返回指定的属性值。

function pick<T, U extends keyof T>(data: T, keys: U[]): {[K in U]: T[K]} {
    const temp: any = {};
    for (let key of keys) {
        temp[key] = data[key];
    }
    return temp;
}

上面代码中定义了两个范型T和U,T表示对象,U被限定为T的属性名(U extends keyof T),返回值的类型为{[K in U]: T[K]},in的作用就是遍历U这个数组。

image.png

可以看到数组元素被限制了只能是user对象里的key

image.png

可以推导出新对象的TypeScript类型。

实现useRequest

import { useEffect, useState } from 'react';

// 模拟请求接口,返回用户列表
function getUsers(): Promise<{ name: string }[]> {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve([
        {
          name: 'tom',
        },
        {
          name: 'jack',
        },
      ]);
    }, 1000);
  })
}

const App = () => {

  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState<Awaited<ReturnType<typeof getUsers>>>([]);
  const [error, setError] = useState(false);

  useEffect(() => {
    setLoading(true);
    getUsers().then((res) => {
      setUsers(res);
    }).catch(() => {
      setError(true);
    }).finally(() => {
      setLoading(false);
    })
  }, []);

  if (loading) {
    return (
      <div>loading...</div>
    )
  }

  if (error) {
    return (
      <div>error</div>
    )
  }

  return (
    <div>
      {users.map(u => (
        <div key={u.name}>{u.name}</div>
      ))}
    </div>
  );
};

export default App;

这个例子实现了从后端请求用户列表并渲染。在加载数据时增加了loading效果。

 const [users, setUsers] = useState<Awaited<ReturnType<typeof getUsers>>>([]);
  • typeof getUsers 获取getUsers函数类型
  • ReturnType 获取某个函数的返回值
  • Awaited 如果函数返回值为Promise,这个可以获取到最终的值类型

如果每个请求都这么写比较麻烦,所以封装下 useRequest

function useRequest<T extends () => Promise<unknown>>(
  fn: T,
): { loading: boolean; error: boolean; data: Awaited<ReturnType<T>> } {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [data, setData] = useState<any>();

  useEffect(() => {
    setLoading(true);
    fn()
      .then((res) => {
        setData(res);
      })
      .catch(() => {
        setError(true);
      })
      .finally(() => {
        setLoading(false);
      });
  }, []);

  return {
    loading,
    error,
    data,
  };
}
const {loading, error, data: users} = useRequest(getUsers);

image.png

推导出的data类型正确。 但是上边封装可能导致bug,如果请求失败,users为空,直播使用会报错。改造一下。

image.png

image.png

如果未请求成功,返回datanull。 为接口请求增加参数。

image.png

image.png

请求传参也能够正确推导出请求函数的参数类型。

总结

主要介绍了 U extends keyof T, {[K in U]: T[K]}, Awaited, ReturnType, Parameters 的使用,Awaited可以取到返回为Promise类型的函数的最终值类型。

参考: zustand源码学习