【问题标题】:How to set a type to be a string but not allowing some specific values?如何将类型设置为字符串但不允许某些特定值?
【发布时间】:2022-07-22 22:27:13
【问题描述】:

我通常使用类型别名来限制可能的字符串值:

type MyType = 'string1' | 'string2' | 'string3';

这在 switch 语句中是少数,可以根据这个值来完成特定的工作。

但是,是否有可能有一个 属于此字符串的类型?

这是live sample of what I'm trying to achieve

基本上,我从 api 获取数据。数据包含几个混合项目,其 type 属性定义项目包含的数据类型。

// Get data from an API
const data: Contact[] = [
  {
    type: 'customer', accountId: 42, email: 'bill@corp.bzh'
  },
  {
    type: 'supplier', deliveryArea: 'Europe', email: 'support@corp.com'
  },
  {
    type: 'AnotherTypeOfContact', email: 'rene@lataupe.com'
  }
];

我映射到的位置


type ContactBase = {
  email: string;
}

type Customer = ContactBase & {
  type: 'customer';
  accountId: number;
}

type Supplier = ContactBase & {
  type: 'supplier';
  deliveryArea: 'Europe'
}

type BasicContact = ContactBase & {
  type: string; // Should be any other value than the one set before
}

type Contact = Customer | Supplier | BasicContact;

我想迭代数据并为某些类型(但不是全部)应用特定行为,并为其他类型回退到简单的行为。

但是,这不会编译。

这是我尝试过的:

// Loop over data, do something specific for well known types and fallback for others
for (let i = 0; i < data.length; i++) {
  const item = data[i];

  switch (item.type) {
    case 'supplier':
      console.log(`${item.email} is a supplier which ships in ${item.deliveryArea}`);
      break;
    case 'customer':
      console.log(`${item.email} is a customer with account id ${item.accountId}`);
      break;
    default:
      console.log(`${item.email} is a contact of type ${item.type}`)
      break;
  }
}

一旦每个众所周知的类型都有一个专用的case 语句,它就会停止编译。

如果我从 BasicContact 类型中删除 type,它不会编译。

我也尝试使用type: Exclude&lt;string, 'customer' | 'supplier'&gt; 排除字符串,但仍然无法编译。

如何解决?

【问题讨论】:

  • 为什么使用 lowerPascalCase 类型的非常规命名?您能否将它们修改为 UpperPascalCase 以免分散您对问题的注意力?
  • 名称已更改。
  • TS 目前没有 否定类型,因此 TypeScript 中没有特定类型可以按照您想要的方式工作。见ms/TS#48073。可能有解决方法,但我不知道您是否想要其中的任何一个。我应该将以上内容写成答案,还是您专门寻找解决方法?

标签: typescript


【解决方案1】:

您不能从 string 类型中排除特定的字符串文字。 (这很酷,但你不能[编辑:至少,not yet,一如既往地感谢jcalz!]。:-))

相反,您可以像这样定义Contact 类型:

type SpecificContact = Customer | Supplier;
type Contact = SpecificContact | BasicContact;

然后有一个类型谓词告诉您联系人是特定类型还是一般类型:

function isSpecificContact(contact: Contact): contact is SpecificContact {
    return contact.type === "supplier" || contact.type === "customer";
}

然后循环可以根据是否是特定类型的联系人进行分支:

for (let i = 0; i < data.length; i++) {
    const item = data[i];

    if (isSpecificContact(item)) {
        switch (item.type) {
            case "supplier":
                console.log(`${item.email} is a supplier which ships in ${item.deliveryArea}`);
                break;
            case "customer":
                console.log(`${item.email} is a customer with account id ${item.accountId}`);
                break;
        }
    } else {
        console.log(`${item.email} is a contact of type ${item.type}`);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2011-03-25
    • 1970-01-01
    • 2015-10-04
    • 2013-09-04
    相关资源
    最近更新 更多