Apl*_*123 6 generics metaprogramming typescript
考虑以下代码:
type TestTuple = [
{ test: "foo" },
{
test: "bar";
other: 1;
}
];
type Foo<Prop extends string> = TestTuple extends Record<Prop, string>[]
? true
: false;
type X = Foo<"test">;
type Prop = "test";
type Y = TestTuple extends Record<Prop, string>[]
? true
: false;
// X is type false
const x: X = false;
// Y is type true
const y: Y = true;
Run Code Online (Sandbox Code Playgroud)
类型Foo和Y完全相同,除了Foo有一个泛型参数Prop,而Y只使用一个名为Prop的类型别名(类型别名不是必需的,Y可能只是,TestTuple extends Record<"test", string>[] ? true : false但我想让它们的声明完全相同)。所以,Foo<"test">(它是 type 的别名X)并且Y应该具有相同的类型,对吗?显然不是。Xas typefalse而Yis type true。将other属性更改TestTuple为字符串或完全删除属性会导致X和Y为真,这是预期的行为。
所以,我的问题是:这是为什么?这是编译器中的错误吗?如果是这样,是否已经提交了我无法找到的问题?或者,这是在打字稿中处理泛型的某种奇怪方式吗?
更新:TypeScript 4.2 已修复此问题:Playground 代码链接
在减少到以下最小示例后,我已就此提交了microsoft/TypeScript#41613 :
type What<K extends string> =
{ x: { y: 0, z: 1 } } extends { x: { [P in K]: 0 } } ? true : false;
type Huh = What<"y">; // expect true but got false!
Run Code Online (Sandbox Code Playgroud)
TypeScript 首席架构师Anders Hejlsberg评论道:
在确定是否推迟条件类型的解析时,我们将检查类型和扩展类型的“最许可实例化”联系起来。最允许的扩展类型实例化的约束最终是
{ x: { [index: string]: 0 } },但实际上应该是{ x: { } }。这是一个简单的修复,我将把它包含在这个 PR 中。
因此,希望它最终能在新的 PR中得到修复,并可能由 TypeScript 4.2 合并到 TypeScript 中。(更新:它已被合并。)如果是这样,我希望这应该解决您问题中的问题,其中{x: ...}我们不是用 包装索引类型,而是用元组类型包装它。
在那之前,您应该考虑使用一种解决方法,例如@Temoncher 的回答中的解决方法。