V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
november
V2EX  ›  问与答

用 typescript 写了个函数,频频报错,请教如何解决

  •  
  •   november · 2021-02-03 12:07:59 +08:00 · 1773 次点击
    这是一个创建于 1420 天前的主题,其中的信息可能已经有所发展或是发生改变。

    typescript 初学者开始用 typescript 试着写点东西,却各种报错。遂来请教各位。

    下面的函数作用是将两个对象合并,并返回合并结果。

    function _merge<T extends U, U> (target: T, source: U) : T {
      for (let key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          const value = source[key]
          if (isObject(target[key]) && isObject(value)) {
            target[key] = _merge(target[key], value)
          } else if (isObject(value)) {
            target[key] = _merge({}, value)
          } else if (isArray(value)) {
            target[key] = _merge([], value)
          }
        }
      }
      return target
    }
    

    然后在target[key] = _merge({}, value)这段代码中的target[key]的错误是

    Type 'U[Extract<keyof U, string>]' is not assignable to type 'T[Extract<keyof U, string>]'.
     Type 'U' is not assignable to type 'T'.
      'T' could be instantiated with an arbitrary type which could be unrelated to 'U'.ts(2322)
    

    {} 又有错误

    Argument of type '{}' is not assignable to parameter of type 'U[Extract<keyof U, string>]'.ts(2345)

    最后在 target[key] = _merge([], value) 在的 [] 也有问题

    Argument of type 'undefined[]' is not assignable to parameter of type 'never'.ts(2345)

    请求如何解决上面的问题?

    13 条回复    2021-02-04 15:43:36 +08:00
    november
        1
    november  
    OP
       2021-02-03 13:02:49 +08:00
    求个大佬给个解决思路。
    BingoXuan
        2
    BingoXuan  
       2021-02-03 13:06:47 +08:00 via Android
    要不看一下 Object.assign 的签名
    Justin13
        3
    Justin13  
       2021-02-03 13:07:18 +08:00 via Android
    november
        4
    november  
    OP
       2021-02-03 13:11:40 +08:00
    @BingoXuan 请问怎么查看签名?
    BingoXuan
        5
    BingoXuan  
       2021-02-03 13:22:30 +08:00
    @november
    我在 webstorm 里面对应的签名来自 https://github.com/microsoft/TypeScript/blob/master/lib/lib.es2015.core.d.ts
    签名是 assign<T, U>(target: T, source: U): T & U;
    SxqSachin
        6
    SxqSachin  
       2021-02-03 13:32:59 +08:00
    同等大佬回答,我自己写这类方法的时候是最后返回的时候带一个 as T
    sillydaddy
        7
    sillydaddy  
       2021-02-03 13:53:55 +08:00
    加一个 as any,就可以解决:
    target[key] = _merge({} as any, value)
    target[key] = _merge([] as any, value)

    虽然取巧(因为没有明确类型),但因为显而易见,所以不会造成错误。否则需要好好啃一啃 TypeScript 的类型系统。
    mxT52CRuqR6o5
        8
    mxT52CRuqR6o5  
       2021-02-03 14:04:52 +08:00
    写不出类型安全的很正常,你这种情况应该就是写不出来的,用各种 any 绕过去就行了
    其他强类型语言基本都写不出这种通用的 merge 函数吧,java 如果用反射来实现保证不了类型安全吧
    chenluo0429
        9
    chenluo0429  
       2021-02-03 14:08:34 +08:00 via Android
    你虽然用了 typescript,但是你的代码实际上一点都不 type 。_merge 的参数要求 target 的类型为 source 的子类,但是_merge({}, value)中{}怎么保证是 value 的子类?你写了不符合 type 的脏代码,要么 ts-ignore,要么就上 any
    november
        10
    november  
    OP
       2021-02-03 14:19:24 +08:00
    @BingoXuan
    我用的 vscode,我想应该是一样的。不过我这里不是函数声明的时候报错,而是内部实现时,赋值报错。


    @sillydaddy @mxT52CRuqR6o5
    对象那行用 any 可以绕过去,但是数组那行还是报错说,不能赋值给 nerver 。
    november
        11
    november  
    OP
       2021-02-03 14:35:48 +08:00
    @chenluo0429

    说得有点道理,那我改成了这样子:_merge<T, U> (target: T, source: U) : (T & U)

    但是这样的话,每次访问 T[key] 的时候,除非进行断言 (<T&U>T)[key],否则都报错。
    Type 'Extract<keyof U, string>' cannot be used to index type 'T'.ts(2536)

    另外,(<T&U>target)[key] = _merge({}, value)这一行,对于(<T&U>target)[key]依然有错误。

    Type '{} & U[Extract<keyof U, string>]' is not assignable to type '(T & U)[Extract<keyof U, string>]'.ts(2322)

    请问这一行怎么弄?
    mxT52CRuqR6o5
        12
    mxT52CRuqR6o5  
       2021-02-04 13:31:28 +08:00
    @november
    因为 array 也是 object,你这条分支是走不到的,类型就成了 never
    november
        13
    november  
    OP
       2021-02-04 15:43:36 +08:00
    @mxT52CRuqR6o5
    啊,是,你说得对。平时摸鱼太多了,一些基本知识都忽略了。。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5818 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 02:45 · PVG 10:45 · LAX 18:45 · JFK 21:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.