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

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

  •  
  •   johnnyNg · 54 天前 · 1055 次点击
    这是一个创建于 54 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如我想要 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
        1
    PainAndLove   54 天前   ♥ 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
    }
    ];
        2
    Hypn0s   54 天前   ♥ 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
    }
    ];

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

    手机打字,单引号不正确
        8
    minsheng   54 天前 via iPhone
    哦,看楼上的例子,枚举的字面值本身也可以做类型,那么

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

    即可
        9
    PainAndLove   54 天前
    @minsheng 嗯,我也试出来了, 但是感觉这样写太不直观了。 还是分成 2 个 interface 好一点
        10
    minsheng   53 天前
    @PainAndLove 编码上确实不是很直观,但是语义上这边相当于定义了一个简单的 type-level function,我觉得更清楚,更方便代码复用。看个人喜好吧,如果只有一两处使用,interface 自然是不错的选择。
        11
    zbinlin   53 天前
    可以用 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: '',
        }
    ];
        12
    ericgui   53 天前
    老铁,您能用 Gender 吗?别用 sex
        13
    PainAndLove   51 天前
    @luob
    这个需求如果放在函数中,可以通过函数的重载来实现。和这里定义 2 个 interface 是一样的性质
        14
    fishlium   48 天前
    @minsheng 这个应用场景下 type Data 怎么放到 interface Person 下呢?
        15
    minsheng   47 天前 via iPhone
    @fishlium 这里就需要一个 generic interface:interface Person<T extends Gender> { gender: Gender; someFieldA: FieldA<T>; someFieldB: FieldB<T> }
        16
    fishlium   47 天前
    @minsheng 谢谢,我也是这样想的,确认一下有没有更好的写法
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1304 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 27ms · UTC 23:34 · PVG 07:34 · LAX 15:34 · JFK 18:34
    ♥ Do have faith in what you're doing.