根据先前使用的数值缩小文字联合。

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

Narrow down literal unions based on previously used values

问题

// 场景如下:

type Option = 'a' | 'b' | 'c' | 'd';

type Question = {
  message: string;
  options: Option[];
  default: Option // 这里是问题所在
}

// 我想让 `default` 属性是 `options` 中的一个选项。例如:

const q1: Question = {
  message: '第一个问题',
  options: ['a', 'b'],
  default: 'a'
}

const q2: Question = {
  message: '第二个问题',
  options: ['c', 'd'],
  default: 'a' // 我希望这里出错,因为 'a' 不在 'c' | 'd' 中
}

如何实现这一目标?
英文:

The scenario is the following:

type Option = 'a' | 'b' | 'c' | 'd'

type Question = {
  message: string;
  options: Option[];
  default: Option // here's the issue
}

I want the default prop to be the one of the options used inside question.options. For example:

const q1: Question = {
  message: 'first question',
  options: ['a', 'b'],
  default: 'a'
}

const q2: Question = {
  message: 'second question',
  options: ['c', 'd'],
  default: 'a' // I want this to give an error because 'a' is not in 'c' | 'd'
}

How can I achieve this?

答案1

得分: 1

这个可以通过使用 Question 来完成;但是,它将是一个复杂的类型,会导致编译器的性能变差,因为它以2的幂次方增长速度,如果有更多选项(超过10个),编译器将达到其极限并无法编译。

相反,我建议调整 Question,使其接受 Option[] 作为泛型参数,并将该泛型参数的元素类型分配给 default

type Question<T extends Option[]> = {
  message: string;
  options: T;
  default: T[number];
};

最后,我们需要一个通用函数来为我们创建一个问题:

const createQuestion = <T extends Option[]>(question: Question<T>) => question;

用法:

const q1 = createQuestion({
  message: "第一个问题",
  options: ["a", "b"],
  default: "a",
});

const q2 = createQuestion({
  message: "第二个问题",
  options: ["c", "d"],
  default: "a", // 预期错误
});

在线演示

英文:

It can be done just by using Question; however, it will be a complex type that will cause a horrible time for the compiler since it grows at the speed of power of two, and if you have more options (more than 10), the compiler will reach its limits and won't compile.

Instead, I would suggest adjusting Question to accept the Option[] as a generic parameter and assign the type of the elements of that generic parameter to default:

type Question&lt;T extends Option[]&gt; = {
  message: string;
  options: T;
  default: T[number];
};

Lastly, we will need a generic function that would create a question for us:

const createQuestion = &lt;T extends Option[]&gt;(question: Question&lt;T&gt;) =&gt; question;

Usage:

const q1 = createQuestion({
  message: &quot;first question&quot;,
  options: [&quot;a&quot;, &quot;b&quot;],
  default: &quot;a&quot;,
});

const q2 = createQuestion({
  message: &quot;second question&quot;,
  options: [&quot;c&quot;, &quot;d&quot;],
  default: &quot;a&quot;, // Expected error
});

playground

huangapple
  • 本文由 发表于 2023年6月1日 18:46:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76381091.html
匿名

发表评论

匿名网友

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

确定