技术解析

typescript 中 interface 如何根据其中一个属性推断另一个属性
0
2021-08-26 05:12:03
idczone

比如我想要 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 总是呈现为数组形式,没法一个个添加泛型


interface IPersonA {
sex: ESex.Male;
test: string
}
interface IPersonB {
sex: ESex.Female;
test: number
}
const persons: Array = [
{
sex: ESex.Male,
test: 'a'
},
{
sex: ESex.Female,
test: 1
}
];

```javascript
enum Sex {
Male,
Female
}
type Person = {
sex: Sex.Female,
test: number,
} | {
sex: Sex.Male,
test: string,
}
const persons: Array = [
{
sex: Sex.Male,
test: ""
},
{
sex: Sex.Female,
test: 1
}
];
```

嗯,可以用联合类型包起来。
不知道有没有更好的方法

确实是个方法,但是如果属性比较多的话,写起来有点麻烦,我是想使用 extends 关键字实现的,但是 extends 关键字是匹配类型的,但是我这个好像涉及到了具体的值

先分别定义 MalePerson 和 FemalePerson 两个接口,然后定义联合类型,type Person = MalePerson | FemalePerson

看了下类似于 T extends K ? number : string 这样的方式。 但是这个场景套不进去。。

这个可以用 conditional type 做,就是楼上说的 T extends K。你把枚举替换成 type Gender = ‘male’ | ‘female’即可。
手机打字,单引号不正确

哦,看楼上的例子,枚举的字面值本身也可以做类型,那么
type Data = T extends Geneder.Male ? string : (T extends Gender.Female ? number : never)
即可

嗯,我也试出来了, 但是感觉这样写太不直观了。 还是分成 2 个 interface 好一点

编码上确实不是很直观,但是语义上这边相当于定义了一个简单的 type-level function,我觉得更清楚,更方便代码复用。看个人喜好吧,如果只有一两处使用,interface 自然是不错的选择。

可以用 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: '',
    }
];

老铁,您能用 Gender 吗?别用 sex


这个需求如果放在函数中,可以通过函数的重载来实现。和这里定义 2 个 interface 是一样的性质

这个应用场景下 type Data 怎么放到 interface Person 下呢?

这里就需要一个 generic interface:interface Person { gender: Gender; someFieldA: FieldA; someFieldB: FieldB }

谢谢,我也是这样想的,确认一下有没有更好的写法

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服