未按预期推断 TypeScript 类型
TypeScript type not inferred as expected
我有一个用例,我想将一组过滤器定义为一个对象。我想知道究竟有哪些过滤器并为其自动完成,但在过滤器的一般处理中,它可以是任何键,只要它的值符合某些类型即可。我想使用泛型和扩展,这在一定程度上起作用,但在某些情况下,它不会像我期望的那样根据它扩展的类型进行统一。这是我尝试过的和出了什么问题的简化示例:
type Foo = { [key: string]: boolean | string[] }
class Bar<F extends Foo> {
constructor(public arg: F) {}
}
const bar = new Bar({ foo: false, bar: [] })
// Reported as always being false.
console.log(bar.arg.foo)
for (const n of bar.arg.bar) {
// Property 'includes' does not exist on type 'never'. ts(2339)
n.includes("x")
}
我希望它推断出 boolean
而不是 false
(对于 foo
),以及 string[]
而不是 never[]
(对于 bar
).我假设 extends 没有像我预期的那样统一类型。有没有办法在 TypeScript 中实现这一点?这意味着我会完全了解 Bar
的实例具有属性 foo
和 bar
,但在 class 本身内部,它只知道泛型类型(如,一些对象,而不是知道它的特定键)。
@jcalz 在我的问题的评论中给出的答案是我正在寻找的答案。我最终以类似于他给出的示例的方式实现了它:
type Foo = { [key: string]: boolean | string[] }
type WidenFoo<T extends Foo> = { [K in keyof T]: T[K] extends boolean ? boolean : string[] };
class Bar<F extends Foo> {
arg: WidenFoo<F>
constructor(arg: F) {
this.arg = arg as WidenFoo<F>;
}
}
const bar = new Bar({ foo: false, bar: [] })
bar.arg.foo // boolean
bar.arg.bar // string[]
console.log(bar.arg.foo)
for (const n of bar.arg.bar) {
n.includes("x")
}
正如他提到的,根据 PR ms/TS#10676,将在适用的情况下使用文字类型,并将尽可能具体(狭窄)。据我所知,没有办法让 TypeScript 自动扩展文字类型,所以我们必须自己通过 T extends Type ? Type : ...
技巧来完成。我试过了,它也适用于更复杂的类型,例如我的用例(具有递归类型等)。
我有一个用例,我想将一组过滤器定义为一个对象。我想知道究竟有哪些过滤器并为其自动完成,但在过滤器的一般处理中,它可以是任何键,只要它的值符合某些类型即可。我想使用泛型和扩展,这在一定程度上起作用,但在某些情况下,它不会像我期望的那样根据它扩展的类型进行统一。这是我尝试过的和出了什么问题的简化示例:
type Foo = { [key: string]: boolean | string[] }
class Bar<F extends Foo> {
constructor(public arg: F) {}
}
const bar = new Bar({ foo: false, bar: [] })
// Reported as always being false.
console.log(bar.arg.foo)
for (const n of bar.arg.bar) {
// Property 'includes' does not exist on type 'never'. ts(2339)
n.includes("x")
}
我希望它推断出 boolean
而不是 false
(对于 foo
),以及 string[]
而不是 never[]
(对于 bar
).我假设 extends 没有像我预期的那样统一类型。有没有办法在 TypeScript 中实现这一点?这意味着我会完全了解 Bar
的实例具有属性 foo
和 bar
,但在 class 本身内部,它只知道泛型类型(如,一些对象,而不是知道它的特定键)。
@jcalz 在我的问题的评论中给出的答案是我正在寻找的答案。我最终以类似于他给出的示例的方式实现了它:
type Foo = { [key: string]: boolean | string[] }
type WidenFoo<T extends Foo> = { [K in keyof T]: T[K] extends boolean ? boolean : string[] };
class Bar<F extends Foo> {
arg: WidenFoo<F>
constructor(arg: F) {
this.arg = arg as WidenFoo<F>;
}
}
const bar = new Bar({ foo: false, bar: [] })
bar.arg.foo // boolean
bar.arg.bar // string[]
console.log(bar.arg.foo)
for (const n of bar.arg.bar) {
n.includes("x")
}
正如他提到的,根据 PR ms/TS#10676,将在适用的情况下使用文字类型,并将尽可能具体(狭窄)。据我所知,没有办法让 TypeScript 自动扩展文字类型,所以我们必须自己通过 T extends Type ? Type : ...
技巧来完成。我试过了,它也适用于更复杂的类型,例如我的用例(具有递归类型等)。