简体   繁体   English

如何在 TypeScript 中实现具有条件类型的接口

[英]How to Implement an interface with conditional types in TypeScript

On a personal project I am facing an issue with TypeScript conditional types.在个人项目中,我遇到了 TypeScript 条件类型的问题。 I have basic understanding of conditional types from the TypeScript docs.我对 TypeScript 文档中的条件类型有基本的了解。 I would expect the setup below to work but it gives a type error.我希望下面的设置可以工作,但它会给出类型错误。

Basicaly I am trying to define an interface for a tree node which is loaded from the disk.基本上我正在尝试为从磁盘加载的树节点定义一个接口。 This means that some of the nodes may not be correctly loaded because of missing files etc. So any node implementation either contains Content or Error .这意味着某些节点可能由于缺少文件等而无法正确加载。因此任何节点实现都包含ContentError

interface Content {
  data: number;
}

interface Error {
  code: string;
}

export interface TreeNode<T extends Content | Error> {
  getValue(): T extends Content ? number : string;
}

class ValueNode<ValueType extends Content> implements TreeNode<ValueType> {
  private readonly value: number;
  public constructor(value: number) {
    this.value = value;
  }
 
  public getValue(): number {
    return this.value;
  }
}

I would expect that the implementation of the getValue method would be allowed to return string since the interface is implemented with type extending Content .我希望getValue方法的实现将被允许返回string ,因为接口是使用扩展Content的类型实现的。 But I get this type error intead:但是我收到了这种类型的错误:

  • Property getValue in type ValueNode<ValueType> is not assignable to the same property in base type TreeNode<ValueType> . ValueNode<ValueType>类型中的属性getValue不能分配给基本类型TreeNode<ValueType>中的相同属性。
    • Type () => number is not assignable to type () => ValueType extends Content? number: string Type () => number不可分配给 type () => ValueType extends Content? number: string () => ValueType extends Content? number: string . () => ValueType extends Content? number: string
      • Type number is not assignable to type ValueType extends Content? number: string类型number不可分配给类型ValueType extends Content? number: string ValueType extends Content? number: string

Cleary, I am doing it the wrong way.显然,我做错了。 What would be the correct way to achieve my goal?实现我的目标的正确方法是什么?

As @Dai pointed out , it's better not to shadow the built-in Error type (so that you can use it in your module).正如@Dai 指出的那样,最好不要隐藏内置的Error类型(以便您可以在模块中使用它)。

Here are two alternatives:这里有两种选择:

TS Playground link TS Playground 链接

interface ContentValue {
  data: number;
}

interface ErrorValue {
  code: string;
}

export interface ValueGetter<T> {
  getValue(): T;
}

class ValueNode<T extends ContentValue> implements ValueGetter<ContentValue['data']> {
  public constructor(private readonly value: T) {}
 
  public getValue(): number {
    return this.value.data;
  }
}

// or
class SimpleValueNode<T extends ContentValue> {
  public constructor(private readonly value: T) {}
 
  public getValue(): number {
    return this.value.data;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM