ᴘᴀɴ*_*ᴛɪs 5 generics types typescript
我有一个基本类型Base,我想创建一个对象来保存接收某些子类型Base(ExtendsBaseA或ExtendsBaseB在本例中)并将其映射到另一种类型的函数C。
我试图将“某些子类型Base”声明为<T extends Base>,但类型检查失败,并显示以下内容:
类型“(baseA: ExtendsBaseA) => C”不可分配给类型“(base: T) => C”。
参数“base”和“baseA”的类型不兼容。
类型“T”不可分配给类型“ExtendsBaseA”。
类型“Base”不可分配给类型“ExtendsBaseA”。
类型“Base”中缺少属性“b”。
片段
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;
}
}
Run Code Online (Sandbox Code Playgroud)
关于如何解决这个问题有什么想法吗?
编辑:奇怪的是,如果我改变:
[key: string]: <T extends Base> (base: T) => C
Run Code Online (Sandbox Code Playgroud)
到:
[key: string]: (base: Base) => C
Run Code Online (Sandbox Code Playgroud)
它可以在操场上运行,但当我在本地 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;
Run Code Online (Sandbox Code Playgroud)
请注意,您需要显式声明联合,如上所示BaseUnion。HandlerMap现在我们可以如下定义类型。
type HandlerMap = {
[K in BaseUnion['type']]?: (base: Extract<BaseUnion, { type: K }>) => C
}
Run Code Online (Sandbox Code Playgroud)
如果你检查一下,它看起来像:
type HandlerMap = {
ExtendsBaseA?: (base: ExtendsBaseA) => C,
ExtendsBaseB?: (base: ExtendsBaseB) => C
}
Run Code Online (Sandbox Code Playgroud)
Foo现在你可以像这样定义你的类:
class Foo {
private readonly handlers: HandlerMap;
constructor() {
this.handlers = {
ExtendsBaseA: this.handler // changed the key
}
}
handler(baseA: ExtendsBaseA): C {
return <C>null!;
}
}
Run Code Online (Sandbox Code Playgroud)
就目前而言,这一切都是有效的。不过,您会发现编写一个接受 aHandlerMap和 aBaseUnion并尝试生成 a的类型安全函数是令人沮丧的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
}
Run Code Online (Sandbox Code Playgroud)
TypeScript 编译器的控制流分析不够复杂,无法理解 的参数h[b.type]始终与 的类型完全对应b。相反,它认为h[b.type]接受 的某些组成部分BaseUnion,而 thatb是 的某些组成部分BaseUnion,并且拒绝它们不匹配的可能性。您可以断言它们确实匹配,这可能是您能做的最好的事情:
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
}
Run Code Online (Sandbox Code Playgroud)
希望这有一些帮助。祝你好运!
| 归档时间: |
|
| 查看次数: |
3629 次 |
| 最近记录: |