V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
johnnyNg
V2EX  ›  JavaScript

typescript 中 interface 如何根据其中一个属性推断另一个属性

  •  
  •   johnnyNg · 2019-10-18 15:07:20 +08:00 · 3682 次点击
    这是一个创建于 1623 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如我想要 sex 属性为 male 时,tes 属性为 string,为 female 时,test 属性为 number

    enum ESex {
      Male,
    
      Female
    }
    
    interface IPerson {
      sex: ESex;
    
      test: string | number;
    }
    
    const persons: IPerson[] = [
      {
        sex: ESex.Male,
    
        test: 1
      },
    
      {
        sex: ESex.Female,
    
        test: ''
      }
    ];
    
    

    不能使用泛型,因为 person 总是呈现为数组形式,没法一个个添加泛型

    16 条回复    2019-10-25 14:08:53 +08:00
    PainAndLove
        1
    PainAndLove  
       2019-10-18 16:54:52 +08:00   ❤️ 1
    interface IPersonA {
    sex: ESex.Male;

    test: string
    }
    interface IPersonB {
    sex: ESex.Female;

    test: number
    }
    const persons: Array<IPersonA | IPersonB> = [
    {
    sex: ESex.Male,
    test: 'a'
    },

    {
    sex: ESex.Female,
    test: 1
    }
    ];
    Hypn0s
        2
    Hypn0s  
       2019-10-18 17:05:12 +08:00   ❤️ 1
    ```javascript

    enum Sex {
    Male,
    Female
    }

    type Person = {
    sex: Sex.Female,
    test: number,
    } | {
    sex: Sex.Male,
    test: string,
    }

    const persons: Array<Person> = [
    {
    sex: Sex.Male,
    test: ""
    },
    {
    sex: Sex.Female,
    test: 1
    }
    ];

    ```
    PainAndLove
        3
    PainAndLove  
       2019-10-18 17:12:42 +08:00
    @Hypn0s 嗯,可以用联合类型包起来。
    不知道有没有更好的方法
    johnnyNg
        4
    johnnyNg  
    OP
       2019-10-18 17:20:41 +08:00
    @PainAndLove @Hypn0s 确实是个方法,但是如果属性比较多的话,写起来有点麻烦,我是想使用 extends 关键字实现的,但是 extends 关键字是匹配类型的,但是我这个好像涉及到了具体的值
    luob
        5
    luob  
       2019-10-18 17:26:52 +08:00
    先分别定义 MalePerson 和 FemalePerson 两个接口,然后定义联合类型,type Person = MalePerson | FemalePerson
    PainAndLove
        6
    PainAndLove  
       2019-10-18 17:33:34 +08:00
    看了下类似于 T extends K ? number : string 这样的方式。 但是这个场景套不进去。。
    minsheng
        7
    minsheng  
       2019-10-18 17:41:37 +08:00 via iPhone
    这个可以用 conditional type 做,就是楼上说的 T extends K。你把枚举替换成 type Gender = ‘male’ | ‘female’即可。

    手机打字,单引号不正确
    minsheng
        8
    minsheng  
       2019-10-18 17:43:46 +08:00 via iPhone
    哦,看楼上的例子,枚举的字面值本身也可以做类型,那么

    type Data<T> = T extends Geneder.Male ? string : (T extends Gender.Female ? number : never)

    即可
    PainAndLove
        9
    PainAndLove  
       2019-10-18 22:33:48 +08:00
    @minsheng 嗯,我也试出来了, 但是感觉这样写太不直观了。 还是分成 2 个 interface 好一点
    minsheng
        10
    minsheng  
       2019-10-19 08:43:37 +08:00
    @PainAndLove 编码上确实不是很直观,但是语义上这边相当于定义了一个简单的 type-level function,我觉得更清楚,更方便代码复用。看个人喜好吧,如果只有一两处使用,interface 自然是不错的选择。
    zbinlin
        11
    zbinlin  
       2019-10-19 11:05:08 +08:00
    可以用 type 来定义:

    enum ESex {
        Male,
        Female,
    }

    type IPerson = {
        sex: ESex.Male;
        test: number;
    } | {
        sex: ESex.Female;
        test: string;
    };

    const persons: IPerson[] = [
        {
            sex: ESex.Male,
            test: 1,
        },
        {
            sex: ESex.Female,
            test: '',
        }
    ];
    ericgui
        12
    ericgui  
       2019-10-19 12:07:48 +08:00
    老铁,您能用 Gender 吗?别用 sex
    PainAndLove
        13
    PainAndLove  
       2019-10-21 14:26:59 +08:00
    @luob
    这个需求如果放在函数中,可以通过函数的重载来实现。和这里定义 2 个 interface 是一样的性质
    fishlium
        14
    fishlium  
       2019-10-24 15:17:09 +08:00
    @minsheng 这个应用场景下 type Data 怎么放到 interface Person 下呢?
    minsheng
        15
    minsheng  
       2019-10-25 11:44:19 +08:00 via iPhone
    @fishlium 这里就需要一个 generic interface:interface Person<T extends Gender> { gender: Gender; someFieldA: FieldA<T>; someFieldB: FieldB<T> }
    fishlium
        16
    fishlium  
       2019-10-25 14:08:53 +08:00
    @minsheng 谢谢,我也是这样想的,确认一下有没有更好的写法
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3041 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 12:47 · PVG 20:47 · LAX 05:47 · JFK 08:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.