I有一个通用类测试state,将枚举(类型)映射到特定界面。但是,当我尝试将新对象分配到此。InterfaceType时,打字稿Indypript Indestect Indections类型(&)而不是union(|),该类型会导致类型错误。

问题描述 投票:0回答:1
interface InterfaceOne { fieldOne: string } interface InterfaceTwo { fieldTwo: string } enum Types { One = 'one', Two = 'two' } type TypeMap = { [Types.One]: InterfaceOne [Types.Two]: InterfaceTwo } export default class TestState<T extends Types> { private baseType: T private interfaceType: TypeMap[T] | null constructor(testFieldOne: T, testFieldTwo: TypeMap[T]) { this.baseType = testFieldOne this.interfaceType = testFieldTwo } private init(): void { if (this.baseType === Types.Two) { const testObject: InterfaceTwo = { fieldTwo: 'test' } console.log(this.interfaceType) this.interfaceType = testObject // ❌ TypeScript infers TypeMap[T] as 'InterfaceOne & InterfaceTwo' instead of `InterfaceOne | InterfaceTwo` } } }

我尝试过的是:

解释铸造

this.interfaceType = testObject as TypeMap[Types.Two]

但错误仍然存在。

conding typemap是一个联合(|),而不是交集(&) Typemap定义似乎正确,但是Typescript仍会侵入交叉点。

检查TypeScript是否错误地将Typemap [t]作为所有可能值的相交 看来Typescript基于T.

没有正确分发Typemap [t]
  • 当分配通用映射类型时,打字稿是推断相交类型(&)而不是联合(|)的? 我如何将testObject正确分配到此。InterFaceType而不丢字字错误?
任何洞察力或解决方法都将不胜感激!

    TS游乐场链接
  • 类型不是

    歧视的联合type;确实,它根本不是

    union类型
  • 。因此,检查
TestState<T>

不能缩小明显类型的

this.baseType === Types.Two

,因此不知道

this

具有类型this.interfaceType。 您可以决定尝试告诉TypeScript,通过给出一个

typescript typescript-generics typescript-typings
1个回答
0
投票
参数

将是

this
方法内部的歧视联合类型TestState<Types.One> | TestState<Types.Two>,这将使init()编译无错误:
this
但是,除非已经缩小到这样的结合,否则您无法轻易从任何地方开始。
init()
因此,我们要做的就是将问题移动。
最终,您不能真正同时使用
ControlFlow Analysis
基因。好吧,在打字稿5.9中,我们很可能会看到
microsoft/typeScript#61359启用了一些通用重新限制,但这可能对此示例无济于事。
因此,我们应该放弃控制流分析或仿制药。由于类不能直接是工会,因此我们需要仿制药,因此让我们尝试从控制流分析中重构。一种方法是将诸如
private init(this: TestState<Types.One> | TestState<Types.Two>): void { if (this.baseType === Types.Two) { const testObject: InterfaceTwo = { fieldTwo: 'test' } console.log(this.interfaceType) this.interfaceType = testObject // okay } }
之类的检查替换为单个通用
索引
,以替换为像

init()
这样的“处理”对象。这有类似的效果,但是现在您可以说出类型正在发生的事情,而不是遵循
this

/constructor(testFieldOne: T, testFieldTwo: TypeMap[T]) { this.baseType = testFieldOne this.interfaceType = testFieldTwo this.init(); // error! // 'TestState<T>' is not assignable to 'TestState<Types.One> | TestState<Types.Two>' } 控制流。

在这里是这样做的方法:
if (obj.discrim === "x") { } else if (obj.discrim === "y") else

const process = {x: ()=>{}, y: ()=>{}}; process[obj.discrim]()
的类型是el图上的

映射类型

,其中每个属性都是在相应的
if

上运行的函数。因此,有一个else方法可以期望private init(): void { const process: { [P in Types]?: (t: TestState<P>) => void } = { [Types.Two](thiz) { const testObject: InterfaceTwo = { fieldTwo: 'test' } console.log(thiz.interfaceType) thiz.interfaceType = testObject } } process[this.baseType]?.(this); } 作为一个论点。我命名了该参数process,因为它代替了您的示例。 由于已知从一开始就是一个

P

,因此您可以进行分配。

,然后为了实际上
使用,您需要访问Types并调用它(如果存在,则将其作为参数为and的chate链(
TestState<P>
)。因此,我们有
Types.Two
,因为
TestState<Types.Two>

具有通用类型

thiz

,并且
this
具有类型

thiz

。  Typescript能够将
TestState<Types.Two>视为适当的单函数类型的事实,而not
是两个函数的结合(因此,仅接受参数的
启动
的功能是这项工作的核心原因,您可以在
microsoft/typecript#47109
.indercland#47109
.inderction上阅读有关此功能的核心原因
没有,这样做的事情不是很直观。但是,直到又一次,除非打字稿可以将控制流量分析和通用工作无缝地一起进行,否则您需要跳过一些篮球以获取打字稿以了解您的工作。
当然,如果您不太在乎Typescript
认为您在做什么,只是希望它能
accept
,您总是可以使用
typeessertions
(您称之为“铸造”),就像:
process

process[this.baseType]type typey或多或少只是告诉打字稿,它甚至不应该尝试检查您的工作。这是权宜之计,但显然不如重构安全。 这完全取决于您的优先事项。 to代码的链接链接

    

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.