这里为什么要使用ref呢?

来源:3-14 模块化结合typescript - 泛型改造

慕莱坞0998854

2020-10-04

老师在演示useURLLoader的时候,有如下的代码:

function useURLLoader<T>(url: string) {
  const result = ref<T | null>(null);
  const loading = ref(true);
  const loaded = ref(false);
  const error = ref(null);

  axios
    .get(url)
    .then((rawData) => {
      loading.value = false;
      loaded.value = true;
      result.value = rawData.data;
    })
    .catch((e) => {
      loading.value = false;
      error.value = e;
    });
 return {
    result,
    loading,
    error,
    loaded,
  };
}

我在看课程的时候产生了疑问,由于不清楚ref和reactive的具体实现,我只是这样死记下来: 原始类型用ref,对象的话用reactive.
那么这里令我疑惑,为什么这里的result明明是一个对象,却用了ref来包裹呢?
然后我就改写了一下,虽然能成功,但是还是有问题不懂:

function useURLLoader<T extends Object>(url: string) {

  // 问题1
  // reactive<T>(param) ref<T>(param) 
  // 上面这两个式子均表示param是T类型的,对吧?

  // 问题2
  // 为什么以下注释的写法会报错?
  // let result:T = reactive({})
  // 使用Object.create(null)却是可以的?
  let result:T = reactive(Object.create(null))
  const loading = ref(true);
  const loaded = ref(false);
  const error = ref(null);

  axios
    .get(url)
    .then((rawData) => {
      loading.value = false;
      loaded.value = true;
	  
	  // 问题三 
	  // 把鼠标放在rawData上面 显示它的类型为AxiosResponse<any>
	  // 那么raw.data的类型也是any
	  // 可是我在之前声明了result要为T类型并且T extends Object
	  // 这TS总该提示我一下吧?
	  // 可是这也没提示啊
      result = rawData.data
    })
    .catch((e) => {
      loading.value = false;
      error.value = e;
    });
  return {
    result,
    loading,
    error,
    loaded,
  };
}





写回答

1回答

张轩

2020-10-05

同学你好 谢谢你很长的问题 

问题 一 理解是正确的,其实可以去看定义文件,看了就清楚很多啦

问题二 Object.create(null) 返回的是 any 类型,而 { } 就是一个 { } 类型, { } 类型不等于 T 类型。 所以第一个不会报错. 而且你这里写法有点问题,不一样指定 let result:T 它为 T 类型,这里类型推论会帮助你的,去掉这个定义你可以看到它真实被推断的类型

问题三 你的result 确实是 T extends  Object 的,我这里是能自动联想出 Object 上的一些方法的。//img1.sycdn.imooc.com/szimg/5f7b26a1094f167f13540424.jpg


最后,关于 ref 和 reactive,没必要死记硬背,我们完全可以对照 js 的概念来记。我在课中也讲过了

const a = 1 || {} || '1' 也可以等于对象 各种类型都可以 对应 ref
const obj = { name: 'a', age: 20 } 一个对象,对应 reactive

这样理解就非常清楚了

0
1
慕莱坞0998854
谢谢老师耐心的回答!但是我还是想说一个。对于第三个问题,我的意思是raw.data是any类型的,而result是T extends Object类型的,那么写下 result = raw.data这一句的时候:1> any类型是不是意味着不做类型检查了?毕竟any可能是数字,字符等不是Object类型的。这里应该会有代码提示警告啊,我觉得TS是比较严谨的语言,为什么这里可能出现类型不匹配的情况它却没有提示呢?2> 因为TS不知道result到底是什么类型的,所以我之前要声明let result:T 这样指定result为T类型
2020-10-06
共1条回复

Vue3 + TS 仿知乎专栏企业级项目

带你完成前后端分离复杂项目,率先掌握 vue3 造轮子技能

3142 学习 · 2313 问题

查看课程