一起养成写作习惯!这是我参与「掘金日新计划 · 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; }