繁体   English   中英

另一个联合类型中的打字稿联合字符串文字

[英]Typescript union string literal in another union type

type Status = 'Active' | 'Pending' | 'Failed';

type User = {
  name: string;
  age: number;
  status: 'active' // how to get autocomplete, it's lowercase??
} | {
  error: string;
  id: string;
  status: 'failed' // can it be something like Status['Failed']
} |
{
  id: string;
  status: 'pending'
}

给定Status作为字符串联合类型,有时需要在另一个复杂对象类型中使用该类型。 每个状态值的不同字段结构。

创建具有status字段的User时如何确保类型安全?

我想重用相同的类型,如下所示

const fooBarFn(status: Status) {
  if (status === 'Pending') {
    return {
      id: '123',
      status
    }
  }
  // rest of fn
}

以上是否有任何其他模式或最佳实践?

一些解决方案

type RecordX<K extends keyof any> = {
  [P in K]: P;
};

type Status = 'Active' | 'Pending' | 'Failed';

type User<T extends RecordX<Status>> = {   // how to default assign
  name: string;
  age: number;
  status: T['Active']
} | {
    error: string;
    id: string;
    status: T['Failed']
  } |
{
  status: T['Pending']
}

const user: User = {   // need the template type parameter
  name: 'foobar';
  age: 99,
  status: 'NotWorking'  // not working
}

如何默认第一个泛型参数,以便用户无需提供类型

您可以通过使用enum关键字来实现这一点,如下所示:

enum Status {
  ACTIVE = 'ACTIVE',
  PENDING = 'PENDING',
  FAILED = 'FAILED',
}

type User = {
  name: string;
  age: number;
  status: Status.ACTIVE;
} | {
  error: string;
  id: string;
  status: Status.FAILED;
} |
{
  id: string;
  status: Status.PENDING;
}

稍后您可以执行此操作来检查User输入。

const user: User = { ... }

if (user.status === Status.PENDING) {
  // Do something if status is pending
}

一种可能的方法是根据User定义Status ,而不是反过来。 这样您就不必重复自己,也不必尝试让编译器自动完成各个状态。 它看起来像这样:

type User = {
    name: string;
    age: number;
    status: 'Active'
} | {
    error: string;
    id: string;
    status: 'Failed'
} | {
    id: string;
    status: 'Pending'
}

type Status = User['status'];
// type Status = "Active" | "Failed" | "Pending"

通过使用"status"索引区分的联合类型User ,我们得到Status所需的联合类型

Playground 代码链接

首先将文字Status转换为对象格式

type Intermediate = {
  Active: 'Active';
  Pending: 'Pending';
  Failed: 'Failed';
}

然后分配为状态的通用类型

type RecordX<K extends keyof any> = {
  [P in K]: P;
};

type Status = 'Active' | 'Pending' | 'Failed';

type User<T extends RecordX<Status> = RecordX<Status>> = {
  name: string;
  age: number;
  status: T['Active']
} | {
  error: string;
  id: string;
  status: T['Failed']
} |
{
  status: T['Pending']
}

const user: User = {
  name: 'foobar';
  age: 99,
  status: 'Active' // autocomplete works
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM