【问题标题】:Typescript unable to assert the type of a concrete instance that inherits typeTypescript 无法断言继承类型的具体实例的类型
【发布时间】:2020-12-12 04:16:59
【问题描述】:

在以下示例中,我创建了一个具有 TStateTResult 的 concreate 类 Dialog。问题是,当我将它传递给show() 方法时,即使TResult 与传入的组件类型的TResult 匹配,结果也是Unknown 而不是Boolean | undefined

interface DialogBase<TState, _TResult> {
    dialogState: TState;
}

class Test {
    public show<TResult, TState>(
      component: { new(...args: any[]): DialogBase<TState, TResult> }, 
      state: TState): TResult | undefined {
        return;
    }
}

class State {}

class Dialog implements DialogBase<State, Boolean> {
    dialogState: State = new State();
}

const test = new Test();
test.show(Dialog, new State());  // return type Unknown

我缺少什么让 typescript 将 show 方法的返回类型断言为 DialogBase 的类型化 TResult?

我什至可以将组件的类型移动到泛型中,但它仍然无法识别返回类型:

interface DialogBase<TState, _TResult> {
    dialogState: TState;
}

class Test {
    public show<TResult, TState, TDialog extends DialogBase<TState, TResult>>(
      component: { new(...args: any[]): TDialog  }, 
      state: TState): TResult | undefined {
        return;
    }
}

class State {}

class Dialog implements DialogBase<State, Boolean> {
    dialogState: State = new State();
}

const test = new Test();
test.show(Dialog, new State());  // return type Unknown

【问题讨论】:

  • 似乎没有一个具体的属性来接受这个值,你不能这样做。
  • 如果您没有为 TS 编译器提供任何提示,TS 无法确定您的返回类型
  • @captain-yossarian TResult 的方法与 DialogBase 的 TResult 相同。如果我传入一个 DialogBase,为什么它不能识别 TResult 是一个布尔值?

标签: typescript


【解决方案1】:

也许你可以通过提供一些提示帮助 TS 解决这个问题?

interface DialogBase<TState, TResult> {
    dialogState: TState;
    isHidden: TResult;
}

class Test {
    public show<TResult, TState>(
      component: { new(...args: any[]): DialogBase<TState, TResult> }, 
      state: TState): TResult | undefined {
        return;
    }
}

class State {}

class Dialog implements DialogBase<State, Boolean> {
    dialogState: State = new State();
    isHidden = false;
}

const test = new Test();
test.show(Dialog, new State());

【讨论】:

  • 虽然这确实解决了问题,但它引入了一个新问题。现在任何创建对话框的人都必须创建一个从未使用过的属性。不确定以一种换另一种是否有价值。
  • 就像它只是必须有一个属性。即使我使用Omit&lt;&gt; 它仍然不知道。
  • 我尝试将属性设为可选isHIdden?: TResult,如果您不实现该属性,它不知道,但如果您实现它,那么它确实......太奇怪了。
  • 如果我在您的示例中将DialogBase 更改为abstract classabstract dialogState 并设置isHidden: TResult | undefined 那么其他程序员可以忽略isHidden 属性而无需实现任何不确实需要。
【解决方案2】:

IT 更多的是解释而不是答案。 请看下一个示例,它与您的相同:

function foo<T>(arg: number): T | undefined {
    return 
}

/**
 * unknown - because TS is unable to figure out what type you are going to return
 */
const result = foo(42)

为了帮助 TS 编译器找出你要返回的类型,你应该为泛型提供一些限制。

例如,您可以这样做:

function foo<T extends Array<number>>(arg: number): T | undefined {
    return 
}

const result = foo(42) // number[] | undefined

在这种情况下,TS 知道您将返回 number[] 或 undefined。

你甚至可以做得更多。

您可以提供重载:

function foo(arg:string):number;
function foo(arg:number):string;
function foo<T extends Array<number>>(arg: number|string): T | undefined {
    return 
}

const result = foo(42) // string
const result2 = foo('42') // number

现在,TS 知道,如果您提供 number,您将收到 string,反之亦然。

它有什么帮助。

【讨论】:

  • 就不一样了,因为我的例子中传递的参数是同一个泛型类型。您的参数不是通用的,因此打字稿无法断言类型。
  • 您的最后一个示例可以是Simplified by generics,因为即使从未明确设置类型,typescript 也可以在简化示例中断言类型。
猜你喜欢
  • 2020-11-01
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 2020-12-01
  • 2020-01-05
  • 1970-01-01
  • 1970-01-01
  • 2019-06-08
相关资源
最近更新 更多