Union type mapped to an object with single key

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

Union type mapped to an object with single key

问题

有没有一种方法可以创建一个只有一个键,该键是字符串联合类型中的一个字符串的对象类型?

示例:

type Key = "a" | "b" | "c"

const result = {
  a: "hello there"
}

const result2 = {
  b: "General Kenobi"
}

const result3 = {
  c: 2137
}

// 所有上面的类型在映射之后应该是正确的

const wrongType = {
  a: "hello there";
  b: "General Kenobi";
}

const wrongType2 = {};

// 这些应该是错误的,因为要么不是只有一个键的对象,要么根本没有键
英文:

Is there a way to create an object type with a single key that is one of the strings from the string union type?

Example:

type Key = "a" | "b" | "c"

const result = {
  a: "hello there"
}

const result2 = {
  b: "General Kenobi"
}

const result3 = {
  c: 2137
}

// All types above should be correct after mapping

const wrongType = {
  a: "hello there";
  b: "General Kenobi";
}

const wrongType2 = {};

// Those should be wrong because either it's not a single-key object, or it doesn't have keys at all

答案1

得分: 1

你可以使用映射类型来实现这个。

type Keys = "a" | "b" | "c";

type T = {
  [key in Keys]: { [k in key]: unknown } & {
    [k in Exclude<Keys, key>]?: never;
  };
}[Keys];

因此,我们生成了一个类型,它是三个对象的联合类型,其中每个对象明确说明如果一个属性存在,其他属性就不应存在。所生成的类型如下:

type T =
  | { a: unknown; b?: undefined; c?: undefined }
  | { b: unknown; a?: undefined; c?: undefined }
  | { c: unknown; a?: undefined; b?: undefined };

注意:仅仅使用以下代码:

type T = {
  [key in Keys]: { [k in key]: unknown }
}[Keys];

不会起作用的,因为没有辨别属性的联合类型不执行多余属性检查

英文:

You can achieve this using mapped types.

type Keys = &quot;a&quot; | &quot;b&quot; | &quot;c&quot;;

type T = {
  [key in Keys]: { [k in key]: unknown } &amp; {
    [k in Exclude&lt;Keys, key&gt;]?: never;
  };
}[Keys];

So, we generate a type that is a union of three objects where each object explicitly states that if one property is present others should not be present. So, the generated type is the following:

type T =
  | { a: unknown; b?: undefined; c?: undefined }
  | { b: unknown; a?: undefined; c?: undefined }
  | { c: unknown; a?: undefined; b?: undefined };

<br>

NOTE: Just doing the following:

type T = {
  [key in Keys]: { [k in key]: unknown }
}[Keys];

would not work because Unions without discriminant properties do not perform excess property checking.

答案2

得分: 0

使用名为ts-xor的库可以实现这一点:

import { XOR } from 'ts-xor'

let test: <A, B>
type Key = XOR<{ a: string }, XOR<{ b: string }, { c: string }>>

// OK!
const result: Key = {
  a: "hello there"
}

// OK!
const result2: Key = {
  b: "General Kenobi"
}

// OK!
const result3: Key = {
  c: 2137
}

// Error due to no matching type
const wrongType: Key = {
  a: "hello there",
  b: "General Kenobi",
}

// Also errors
const wrongType2: Key = {}
英文:

One way to do that is using the library called ts-xor:


import { XOR } from &#39;ts-xor&#39;

let test: &lt;A, B&gt;
type Key = XOR&lt;{ a: string }, XOR&lt;{ b: string }, { c: string }&gt;&gt;

// OK!
const result: Key = {
  a: &quot;hello there&quot;
}

// OK!
const result2: Key = {
  b: &quot;General Kenobi&quot;
}

// OK!
const result3: Key = {
  c: 2137
}

// Error due to no matching type
const wrongType: Key = {
  a: &quot;hello there&quot;,
  b: &quot;General Kenobi&quot;,
}

// Also errors
const wrongType2: Key = {}

huangapple
  • 本文由 发表于 2023年7月23日 15:17:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76747041.html
匿名

发表评论

匿名网友

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

确定