美文网首页
TypeScript全解:深入对象与函数(下)

TypeScript全解:深入对象与函数(下)

作者: littleyu | 来源:发表于2023-06-10 21:37 被阅读0次

    函数重载(overload)

    什么是函数重载?简单来说就是同名的函数,这个概念是从 java 来的

    我们来看这个需求,一个方法接受的参数有两种情况,可能是 number,可能是 string

    如果用 TS 来实现,非常简单

    class X {
      method(n: number | string) {
        /* ... */
      }
    }
    

    但是 java 不支持这种情况的联合类型,但是遇到这种需求该怎么办呢?java 的设计者当时又不想直接弄出这么个联合类型,那干脆让一个方法写两遍好了

    class X {
      method(n: number) {
        /* ... */
      }
      method(n: string) {
        /* ... */
      }
    }
    

    于是 java 就诞生了一个新语法,一个类的方法是可以同名的,用你的参数类型和个数来判断会具体执行那个函数(很奇怪的语法吧~)

    所以重载是为了解决 java 的一个问题

    其实在很久之前大家都应该接触过函数重载,在 JQuery 时代的 Selector 一样

    $('#div')
    $(window)
    $...
    

    也许内部使用了大量的 if else,所以说 js 不需要重载这个特性,也能做出一样的效果

    但是说回 TS,我认为只有这些情况可能需要用重载

    一个创建日期的函数,可以接受一个数量 number,也能接受具体的日期

    function createData(n: number): Date
    function createData(year: number, month: number, date: number): Date
     // TODO: 注意:下面这里会和 java 稍微不同一点
    function createData(a: number, b?: number, c?: number): Date { // TODO: 最后一个实现的签名需要兼容上面所有的情况
      if (a !== undefined && b !== undefined && c !== undefined) {
        return new Date(a,b,c)
      } else if (a !== undefined && b === undefined && c === undefined) {
        return new Date(a)
      } else {
        throw new Error('只接受一个或三个参数')
      }
    }
    

    也许也能用联合类型➕if else 实现出来,但是重载会更优雅一点

    但是我个人依然保持能不用就不用的态度看待它,就算遇到这种问题,为何非要用一个函数来解决,用两个不同名称的函数来不香么,createDataByNumber 和 createDataByYMD

    其实如果你是一个库的封装者,像 JQuery 一样,把函数封装的复杂度留给自己,使用函数重载能方便使用者
    但如果你是想把函数的使用权交给用户,就应该多明明几个函数提供用户任意组合使用

    this

    在 TS 中怎么定义 this 的类型呢?

    type Person {
      name: string;
    }
    function fn(this: Person, word: string) { // TODO: 这个地方好奇 this 为什么会在参数上的人,请看我的 javascript-this 文章
      console.log(this.name, word)
    }
    
    fn('hi') // TODO: 报错
    

    this 在参数上了,那么该如何调用呢?看下面几种方法:

    // 强行拼凑出 person.fn()
    const p: Person & { fn: typeof fn } = { name: 'jack', fn }
    p.fn('hi')
    
    // fn.call()
    fn.call({ name: 'jack' }, 'hi')
    
    // fn.apply()
    fn.apply({ name: 'jack' }, ['hi'])
    
    // fn.bind()
    fn.bind({ name: 'jack' })('hi')
    

    ... 与 参数

    剩余参数

    function sum(...x: number[]) {
      return x.reduce((a,b) => a + b, 0)
    }
    
    sum(1)
    sum(1,2,3,4,5)
    sum(1,2,3,4,5,6,7,8,9)
    

    展开参数

    function sum(name: string, ...rest: number[]) {
      fn(...rest)
      // or
      fn.apply(null, rest)
    }
    
    function fn(...x: number[]) {
      console.log(x)
    }
    

    as const

    我们知道 TS 有自动推导

    let a = 'hi'
    

    此时我们很容易看出来 a 的类型是 string
    其实这样可能会有些问题
    理论上来说 a 的类型应该可能是 'hi' 或者 string
    但是这个 TS 怎么知道我们这个 a 是常量(即类型为 'hi')还是 string 呢?

    用 const

    let a = 'hi' as const
    

    不对啊,直接用 const 关键词不就好了

    const a = 'hi'
    

    其实大多数的应用场景在对象上,因为 JS 的 const 就是残废

    const array = [1, 'hi'] as const
    

    参数对象的析构

    type Config = {
      url: string;
      method: 'GET' | 'POST' | 'PATCH';
      data?: number;
    }
    
    // 使用一
    function ajax({ url, method, ...data }: Config) {}
    
    // 使用二
    function ajax({ url, method, ...data }: Config = {url: '', method: 'GET'}) {}
    
    // 使用三
    function ajax({ url, method, ...data } = {url: '', method: 'GET'} as Config) {}
    

    void

    function f1(): void {
      return
    }
    function f2(): void {
      return undefined
    }
    function f3(): void {
    }
    function f4(): void {
      return null // TODO: 报错
    }
    

    相关文章

      网友评论

          本文标题:TypeScript全解:深入对象与函数(下)

          本文链接:https://www.haomeiwen.com/subject/ncmzedtx.html