[译]<<Effective TypeScript>> 高效TypeScript62个技巧 技巧12

162 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情

本文的翻译于<<Effective TypeScript>>, 特别感谢!! ps: 本文会用简洁, 易懂的语言描述原书的所有要点. 如果能看懂这文章,将节省许多阅读时间. 如果看不懂,务必给我留言, 我回去修改.

技巧12: 尽量给整个函数表达式定义类型

js 和 ts 是这样区分函数语句(statement)和函数表达式(expression):

function rollDice1(sides: number): number { /* ... */ }  // Statement
const rollDice2 = function(sides: number): number { /* ... */ };  // Expression
const rollDice3 = (sides: number): number => { /* ... */ };  // Also expression

函数表达式的好处是: 你可以给整个函数表达式定义类型, 而不是分开对每个参数定义类型:

type DiceRollFn = (sides: number) => number;
const rollDice: DiceRollFn = sides => { /* ... */ };

这样做有什么好处吗?

  • 可以减少重复. 比如你有这样几个函数:

    function add(a: number, b: number) { return a + b; }
    function sub(a: number, b: number) { return a - b; }
    function mul(a: number, b: number) { return a * b; }
    function div(a: number, b: number) { return a / b; }
    

    对整个函数进行类型定义, 会更简洁:

    type BinaryFn = (a: number, b: number) => number;
    const add: BinaryFn = (a, b) => a + b;
    const sub: BinaryFn = (a, b) => a - b;
    const mul: BinaryFn = (a, b) => a * b;
    const div: BinaryFn = (a, b) => a / b;
    
  • 另外一个作用就是当你需要写相同类型的函数. 比如 fetch函数对某些资源发起http请求:

    const responseP = fetch('/quote?by=Mark+Twain');  
    // Type is Promise<Response>
    

    通过response.json(),response.text()来获取json类型的数据.:

    async function getQuote() {
      const response = await fetch('/quote?by=Mark+Twain');
      const quote = await response.json();
      return quote;
    }
    // {
    //   "quote": "If you tell the truth, you don't have to remember anything.",
    //   "source": "notebook",
    //   "date": "1894"
    // }
    

    但是这存在一个bug: 如果你请求失败, 你的 response body可能是字符串而不是json格式的数据,比如'404 Not Found' . 你就会返回一个 rejected Promise. 这会掩盖404错误.

    我们可以写一个checkedFetch函数来解决这个问题:

    async function checkedFetch(input: RequestInfo, init?: RequestInit) {
      const response = await fetch(input, init);
      if (!response.ok) {
        // Converted to a rejected Promise in an async function
        throw new Error('Request failed: ' + response.status);
      }
      return response;
    }
    

    但是我们可以写的更简洁:

    const checkedFetch: typeof fetch = async (input, init) => {
      const response = await fetch(input, init);
      if (!response.ok) {
        throw new Error('Request failed: ' + response.status);
      }
      return response;
    }
    

    我们从一个函数语句变成了加了类型的函数表达式. 一方面更简洁了, 另一方面这保证了 checkedFetch 和 fetch 的返回值相同.

    当你写的是return而不是throw. 就会报这个错误:

    const checkedFetch: typeof fetch = async (input, init) => {
      //  ~~~~~~~~~~~~   Type 'Promise<Response | HTTPError>'
      //                     is not assignable to type 'Promise<Response>'
      //                   Type 'Response | HTTPError' is not assignable
      //                       to type 'Response'
      const response = await fetch(input, init);
      if (!response.ok) {
        return new Error('Request failed: ' + response.status);
      }
      return response;
    }