英文:
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<T extends Option[]> = {
message: string;
options: T;
default: T[number];
};
Lastly, we will need a generic function that would create a question for us:
const createQuestion = <T extends Option[]>(question: Question<T>) => question;
Usage:
const q1 = createQuestion({
message: "first question",
options: ["a", "b"],
default: "a",
});
const q2 = createQuestion({
message: "second question",
options: ["c", "d"],
default: "a", // Expected error
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论