我可以为打字稿界面分配2种不同的类型吗?

时间:2020-04-11 14:20:54

标签: typescript

我具有以下界面结构来存储旅行者。

interface Person: {
    age: number,
    name: string
}

interface TravelersDirectory {
    [country: string]: Person[]
}
example:
    travelersDirectory = {
        'India': [
            {
                age: 30,
                name 'X'
            },
            {
                age: 35,
                name 'Y'
            },
        ]
    }

通过新更改,我将使旅行者与旅行者目录脱钩 人员和引用将存储在Travelers目录中。新界面将是:

interface Persons extends Array<Person>

但是由于业务需求,travelerDirectory可以保留(到Persons的)索引或Person对象的

示例:

    const persons = [
            {
                age: 30,
                name 'X'
            },
            {
                age: 35,
                name 'Y'
            },
        ];

    const travelersDirectory = [
        'India': [
            0,
            {
                age: 35,
                name 'Y'
            },              
        ]
    ]

这可能吗?类型(索引和Person对象)可以共存吗?我试图通过对TravellersDirectory界面进行更改来解决问题,但是没有成功。 尝试1:

    interface TravelersDirectory {
        [country: string]: Person[] | number[]
    }

Attempt2:

    interface Persons extends Array<Person | number>

    interface TravelersDirectory {
        [country: string]: Persons
    }

我该怎么办?

注意:所使用的数据结构是符号性的,我无法重新设计它。只有通过使用界面才能解决此问题

检查此链接以查找确切的问题https://stackblitz.com/edit/typescript-ypc59j

2 个答案:

答案 0 :(得分:0)

问题中的第二次尝试是键入此内容的正确方法,但可以简化为:

interface TravelersDirectory {
  [country: string]: Array<Person | number>;
}

经过与OP的反复交流,我发现问题出在其他地方,即这段代码:

function getName(travelersDirectory: TravelersDirectory, country: string, index: number) {
  return travelersDirectory[country][index].name;
}

这是因为travelersDictionary[country][index]可以是Person或数字,因此不能保证属性name的存在。为了解决这个问题,我们需要防止这种情况,并定义如果travelersDictionary[country][index]的结果是数字时应该怎么办。为此,我们可以将结果保存到变量中,并使用typeof来检查结果是否为数字,然后再告诉它如果是Person,将会发生什么情况。

function getName(travelersDirectory: TravelersDirectory, country: string, index: number) {
    const person = travelersDirectory[country][index];
    if (typeof person === "number") {
      // getName was called referencing a number instead of a Person. 
      // Throw Error? Do nothing? Up to you
      throw Error("Can't get name of a number");
    } else {
      // Typescript is smart enough to understand that the variable `person` can't be a number
      // (because we guarded against it in the previous if-expression)
      // so now we can do person.name
      return person.name;
    }
}

Here's a Stackblitz证明了这一点

答案 1 :(得分:-1)

根据您的要求,最简单的解决方案是仅引用TravellersDirectory本身中的可能值:

interface TravelersDirectory {
    [country: string]: Array<Person | number>;
}

如果您希望它更容易阅读,也可以使用类型别名:

type PersonID = number;
type Persons = Array<Person | PersonID>;

interface TravelersDirectory {
    [country: string]: Persons
}

我个人认为,仅使用ID的类型别名并按如下方式声明目录是最易读的方法:

type PersonID = number;

interface TravelersDirectory {
    [country: string]: Array<Person | PersonID>;
}

这还允许您以后将人员ID更改为其他对象(例如对象或字符串),而不是数字(如果需要)。