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

这个 TypeScript 类型应该怎么写?

  •  
  •   rabbbit · 2020-04-23 09:54:21 +08:00 · 1219 次点击
    这是一个创建于 1490 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大致过程就是检查 b 上有没有和 a 相同的属性,如果有就赋值给 a.

    interface A {
      foo: string;
      bar: number;
    };
    const a: A = {
      foo: 'a',
      bar: 1,
    };
    
    interface B extends Partial<A> {
      [propName: string]: any;
    }
    const b: B = {
      foo: 'b',
      bar: 2,
      c: 3,
    };
    
    for (const key of Object.keys(a)) {
      if (b[key]) {
        a[key] = b[key]; // 报错: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'A'.
      }
    }
    
    for (const key of Object.keys(a)) {
      const k = key as keyof typeof a;
      if (b[k]) {
        a[k] = b[k]; // 报错: Type 'string | number' is not assignable to type 'never'.
      }
    }
    

    除了像下面这样给 A 加上 [propName: string] 之外还有别的解决办法吗?

    interface A {
      [propName: string]: string|number;
      foo: string,
      bar: number,
    };
    
    第 1 条附言  ·  2020-04-23 10:35:58 +08:00
    这么写倒是不报错

    ```ts
    for (const key of Object.keys(b)) {
    if (a.hasOwnProperty(key)) {
    const PropDescriptor = Object.getOwnPropertyDescriptor(b, key);
    Object.defineProperty(a, key, PropDescriptor);
    }
    }
    ```
    4 条回复    2020-04-23 15:55:30 +08:00
    blindie
        1
    blindie  
       2020-04-23 11:17:07 +08:00 via Android   ❤️ 1
    let merged = {...a, ...b} ?
    rabbbit
        2
    rabbbit  
    OP
       2020-04-23 11:28:02 +08:00
    @blindie
    这么写应该不行, b 上可能有 a 没有的属性.
    noe132
        3
    noe132  
       2020-04-23 11:39:23 +08:00   ❤️ 1
    a[k] = b[k] 目前是无法做到 sound 的。
    本质上是 ts 无法对 union key 做 narrow 。
    https://github.com/microsoft/TypeScript/issues/13995

    假设你有这么一个函数,能够通过编译检查(在 ts3.4 之前是可以通过检查的)
    const write = <K extends keyof A>(obj:A, key: K, value: A[K]) {
    obj[key] = value
    }

    write(a, 'foo', 1) 是完全符合这个函数的类型声明的。

    左值如果类型是个集合,那么类型是集合所有元素的交集。
    以 a[key] 为例 string & number 得到的结果就是 never 。

    实际上,缺少的是类似 oneof 这样的操作符,将 K 限定在集合中的某一项。

    目前只能使用 (a as any)[key] = b[key] 的方式绕过。类型的健全就必须靠你自己保证。
    blindie
        4
    blindie  
       2020-04-23 15:55:30 +08:00 via Android
    @rabbbit 你既然两个都是 interface 按照 duck typing 的思想没有影响照用呗
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3829 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 10:13 · PVG 18:13 · LAX 03:13 · JFK 06:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.