gpt4 book ai didi

Typescript - 将泛型类型 'not assignable' 绑定(bind)到扩展类型的函数

转载 作者:搜寻专家 更新时间:2023-10-30 21:06:29 25 4
gpt4 key购买 nike

我有一个基本类型 Base我想创建一个对象,其中包含接收 Base 的某些子类型的函数(在本例中为 ExtendsBaseAExtendsBaseB)并将其映射到另一种类型 C .

我试图声明Base 的某些子类型”<T extends Base> ,但类型检查失败并显示以下内容:

Type '(baseA: ExtendsBaseA) => C' is not assignable to type '(base: T) => C'.

Types of parameters 'base' and 'baseA' are incompatible.

Type 'T' is not assignable to type 'ExtendsBaseA'.

Type 'Base' is not assignable to type 'ExtendsBaseA'.

Property 'b' is missing in type 'Base'.

片段

interface Base {
a: string
}

interface ExtendsBaseA extends Base {
b: string
}

interface ExtendsBaseB extends Base {
c: string
}

interface C {}


class Foo {
private readonly handlers: {
[key: string]: <T extends Base> (base: T) => C
}

constructor() {
this.handlers = {
'bar' : this.handler
}
}

handler(baseA: ExtendsBaseA): C {
return <C>null;
}
}

Try it here

关于如何解决这个问题有什么想法吗?

编辑:奇怪的是,如果我改变:

[key: string]: <T extends Base> (base: T) => C

到:

[key: string]: (base: Base) => C

它可以在 playground 上运行,但当我在本地安装的 Typescript 上尝试时却不行。 (都是2.9.1)

最佳答案

由于您计划将 handlers 设为一个映射,其键对应于可区分联合的判别式,因此您应该能够准确地表示该类型。让我充实您必须包括判别式的类型:

interface Base {
type: string
a: string
}

interface ExtendsBaseA extends Base {
type: "ExtendsBaseA"
b: string
}

interface ExtendsBaseB extends Base {
type: "ExtendsBaseB"
c: string
}

interface C { }

type BaseUnion = ExtendsBaseA | ExtendsBaseB;

请注意,您需要显式声明联合,如上面的 BaseUnion 所示。现在我们可以定义类型 HandlerMap 如下。

type HandlerMap = { 
[K in BaseUnion['type']]?: (base: Extract<BaseUnion, { type: K }>) => C
}

如果你检查它,它看起来像:

type HandlerMap = {
ExtendsBaseA?: (base: ExtendsBaseA) => C,
ExtendsBaseB?: (base: ExtendsBaseB) => C
}

现在您可以像这样定义您的 Foo 类:

class Foo {
private readonly handlers: HandlerMap;

constructor() {
this.handlers = {
ExtendsBaseA: this.handler // changed the key
}
}

handler(baseA: ExtendsBaseA): C {
return <C>null!;
}

}

就目前而言,一切正常。尽管如此,您还是会发现编写一个采用 HandlerMapBaseUnion 并尝试生成 C 的类型安全函数会令人沮丧:

function handle<B extends BaseUnion>(h: HandlerMap, b: B): C | undefined {
const handler = h[b.type]
if (!handler) return;
return handler(b); // error, no valid call signature
}

TypeScript 编译器的控制流分析不够复杂,无法理解 h[b.type] 的参数将始终与 b 的类型完全对应。相反,它看到 h[b.type] 接受 BaseUnionsome 成分,并且 b 是 <BaseUnion 的 em>一些 组成部分,并对它们不匹配的可能性犹豫不决。您可以断言它们确实匹配,这可能是您能做的最好的事情:

function handle<B extends BaseUnion>(h: HandlerMap, b: B): C | undefined {
const handler = h[b.type] as ((b: B) => C) | undefined;
if (!handler) return;
return handler(b); // okay
}

希望对您有所帮助。祝你好运!

关于Typescript - 将泛型类型 'not assignable' 绑定(bind)到扩展类型的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50800273/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com