Typescript 不在对象数组上强制执行辨别类型。

huangapple go评论61阅读模式
英文:

Typescript not enforcing discriminated type on array of objects

问题

以下是翻译好的代码部分:

enum Prevals {
  one = 'one',
  two = 'two',
  three = 'three',
}

type PrevalParams = {
  [Prevals.one]: {
    name: string;
    age: number;
  };
  [Prevals.two]: {
    t: 'thing';
  };
  [Prevals.three]: undefined;
}

type PrevalConfig<Id extends Prevals> = {
  id: Id;
  level: 'error' | 'warning';
  params: PrevalParams[Id];
};
const prevals: PrevalConfig<Prevals>[] = [
  {
    id: Prevals.one,
    level: 'warning',
    params: {
      t: 'thing'
    }
  }
]

请注意,翻译后的代码与原始代码相同,只是去除了HTML编码和注释。

英文:

I've created the following set of types (simplified):

enum Prevals {
  one = &#39;one&#39;,
  two = &#39;two&#39;,
  three = &#39;three&#39;,
}

type PrevalParams = {
  [Prevals.one]: {
    name: string;
    age: number;
  };
  [Prevals.two]: {
    t: &#39;thing&#39;;
  };
  [Prevals.three]: undefined;
}

type PrevalConfig&lt;Id extends Prevals&gt; = {
  id: Id;
  level: &#39;error&#39; | &#39;warning&#39;;
  params: PrevalParams[Id];
};

Given the above types, I would expect to be able to assign several PrevalConfig objects to an array and have typescript enforce their parameters. However, it seems to interpret the params as the union of all possible params, rather than as the params associated with the specific ID given.

For example, the following should throw an error but doesn't:

const prevals: PrevalConfig&lt;Prevals&gt;[] = [
  {
    id: Prevals.one,
    level: &#39;warning&#39;,
    params: {
      t: &#39;thing&#39;
    }
  }
]

I believe this is because the type PrevalConfig&lt;Prevals&gt;[] essentially says "an array of PrevalConfig objects where the Id parameter is the union of all possible Prevals." Given that interpretation, it is technically correct that it types the params as "the union of all possible params". However, that's not what I want.

How do I make this work?

(here's a playground with all this pre-loaded)

答案1

得分: 0

同事帮助我解决了这个问题。我一直在对自己说:“我需要`PrevalConfig`成为所有可能的预值配置的并集,而不是参数化类型”,确实有一个(有点奇怪的)typescript 构造用于此:

```typescript
type PrevalConfig = {
  [Id in Prevals]: {
    id: Id;
    level: 'error' | 'warning';
    params: PrevalParams[Id];
  };
}[Prevals];

基本上,你创建了每个预值到其具体类型的映射类型。然后在同一个动作中,你告诉typescript给你该映射类型的所有值的并集。因此,你就拥有了所有可能的预值配置的并集:D。

感谢,匿名同事!


<details>
<summary>英文:</summary>

A colleague of mine just helped me work this one out. I kept saying to myself, &quot;I need `PrevalConfig` to be the union of all possible preval configs, not a parameterized type,&quot; and indeed there&#39;s a (somewhat weird) typescript construct for that:

```typescript
type PrevalConfig = {
  [Id in Prevals]: {
    id: Id;
    level: &#39;error&#39; | &#39;warning&#39;;
    params: PrevalParams[Id];
  };
}[Prevals];

Basically, you create a mapped type of each preval to it's specifically-typed config. Then in the same swoop, you tell typescript to give you the union of all of the values for that mapped type. Thus, you have the union of all possible preval configs :D.

Thanks, anonymous colleague!

huangapple
  • 本文由 发表于 2023年7月11日 04:37:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657181.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定