【发布时间】:2021-03-27 20:33:22
【问题描述】:
具有泛型和对象的条件类型可以正常工作,例如:
interface Bar<T extends Record<string, any>> {
x: T extends { x: number } ? number : string,
y: T extends { y: number } ? number : string,
z: T extends { z: number } ? number : string,
}
const bar: Bar<{x: 1, y: 2, z: ""}> = {
x: 1,
y: 2,
z: 3 // expected error, z supposed to be a string
}
如何将相同的原理应用于泛型数组?也就是说,我如何检查泛型是否包含值?我想要类似的东西
interface Foo<T extends number[]> {
x: T includes 1 ? number : string,
y: T includes 2 ? number : string,
z: T includes 3 ? number : string,
}
const foo: Foo<[1,2]> = {
x: 1,
y: 2,
z: ""
}
但显然 T includes x 不是有效的 TypeScript 语法。这甚至可能吗?
我已经尝试过:
x: T includes 1 ? number : string,
x: T includes [1] ? number : string,
x: T includes Array<1> ? number : string,
它们都不起作用
我可以通过使用T[0] extends 1 和类似方法检查类型参数的特定索引处的特定值来接近我想要的:
interface Foo<T extends number[]> {
x: T[0] extends 1 ? number : string,
y: T[1] extends 2 ? number : string,
z: T[2] extends 3 ? number : string,
}
const foo: Foo<[1,2]> = {
x: 1,
y: 2,
z: 3 // expected error, the type argument doesn't have a number at index 2, so `z` is type string
}
const foo2: Foo<[1,2,4]> = {
x: 1,
y: 2,
z: 3 // expected error, the type argument has 4 at index 2, not 3, so `z` is type string
}
但这取决于顺序。我可以在不依赖订单的情况下做到这一点吗?所以z必须是number,只有当类型参数在它的任何地方都有3,否则string?
【问题讨论】:
-
恐怕我真的很难弄清楚你想要做什么。情况似乎并不相似。在您的对象示例中,不同的属性可以有不同的类型,但在您的数组示例中,
T是extends number[],因此T中的条目必须是数字。您希望何时让x、y或z改为字符串? -
如果您想查看通用参数
[1, 2]是否包含 value1anywhere 在其中,我是 99 %确定你不能在类型系统中这样做。您可以测试类型参数的各个元素,但顺序很重要。 -
你为什么使用元组类型而不是像
1 | 2这样的联合? -
我已删除我的答案并将其折叠到问题中。如果您不喜欢我的更改,请随时将其回滚。将答案复制到问题中不是提出问题的人应该做的事情,但如果发布答案的人这样做也没关系 - 只要发布问题的人也可以。 :-) 我这样做是因为它似乎对这个问题有所帮助,而且我知道我无法进一步提出解决方案。
-
@jcalz - 我怎么没想到?! (不要回答这个问题,我们都知道为什么。:-))Like this?
标签: typescript typescript-generics