V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iPhone12
V2EX  ›  TypeScript

TypeScript 如何实现属性的类型取决于另外一个属性的值?

  •  
  •   iPhone12 · 2022-01-21 20:22:24 +08:00 · 1772 次点击
    这是一个创建于 1070 天前的主题,其中的信息可能已经有所发展或是发生改变。

    代码如下,想要实现 Message 中:playload 的类型取决于 type 的值

    下面已有的写法是不行的。

    
    interface PayloadMap {
      join: PeerInfo;
      offer: RTCSessionDescriptionInit;
      answer: RTCSessionDescriptionInit;
      icecandidate: RTCIceCandidateInit;
      leave: PeerInfo;
    }
    
    // 客户端发送,服务端接受的数据格式
    interface Message {
      type: 'join' | 'offer' | 'answer' | 'icecandidate' | 'leave';
      nick: string;
      id: string;
      
      // playload 的类型取决于 type 的值
      payload: PayloadMap[Message['type']];
    }
    

    比如:

    const m: Message = {
      type: 'join',
      nick: 'Fuck',
      id: '123456',
      payload: {
        // 此时 payload 应该是 PeerInfo 类型
      }
    }
    
    3 条回复    2022-04-14 11:01:49 +08:00
    rabbbit
        1
    rabbbit  
       2022-01-21 20:57:04 +08:00   ❤️ 1
    interface Foo {

    }

    interface Bar {

    }

    interface PayloadMap {
      join: Foo;
      offer: Bar;
    }

    type Message = { [k in keyof PayloadMap]: {
      type: k;
      payload: PayloadMap[k];
    } }[keyof PayloadMap];

    const m: Message = {
      type: 'join',
      payload: {
     }
    }

    const n: Message = {
      type: 'offer',
      payload: {
     }
    }
    iPhone12
        2
    iPhone12  
    OP
       2022-01-21 21:15:21 +08:00
    @rabbbit 学到了,感谢!

    map 出一个 key 对应一个类型,然后联合。妙!
    fifa666
        3
    fifa666  
       2022-04-14 11:01:49 +08:00
    interface PayloadMap {
    join: 'join';
    offer: RTCSessionDescriptionInit;
    answer: RTCSessionDescriptionInit;
    icecandidate: RTCIceCandidateInit;
    leave: 'leave';
    }

    interface Message<T, P extends keyof T> {
    type: P;
    nick: string;
    id: string;
    payload: T[P];
    }


    const m: Message<PayloadMap, 'join'> = {
    type: 'join',
    nick: 'Fuck',
    id: '123456',
    payload: "join"
    };
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5722 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 03:03 · PVG 11:03 · LAX 19:03 · JFK 22:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.