【问题标题】:How to define a private property when implementing an interface in Typescript?在 Typescript 中实现接口时如何定义私有属性?
【发布时间】:2023-04-04 17:20:01
【问题描述】:

我在我的项目中使用 TypeScript,但遇到了一个问题。 我正在定义这样的接口:

interface IModuleMenuItem {
    name: string;
}

我想创建一个从此接口实现的类,但我希望名称是这样的私有属性:

class ModuleMenuItem implements IModuleMenuItem {
    private name: string;
}

我收到以下错误:

类 ModuleMenuItem 错误地实现了接口 IModuleMenuItem。 属性名称在 ModuleMenuItem 类型中是私有的,但在类型中不是私有的 IModuleMenuItem。

在实现接口时如何将属性定义为私有或受保护?

【问题讨论】:

  • 接口基本上是在这里定义什么是公共的。我不确定你有没有办法检查什么是私有的。

标签: reactjs typescript


【解决方案1】:

接口定义了“公共”契约,因此在接口上使用protectedprivate 访问修饰符是没有意义的,我们称之为实现细节。出于这个原因,你不能用一个界面做你想做的事。

如果您想让属性对消费者只读,但在子类中可覆盖,那么您可以执行以下操作:

interface IModuleMenuItem {
     getName(): string;
}

class ModuleMenuItem implements IModuleMenuItem {
    private name;

    public getName() {
        return name;    
    }

    protected setName(newName : string) {
        name = newName;
    }
}

我认为在 TypeScript 2.0(尚未推出)中,如果您在初始化时只读字段之后,您将能够使用 readonly 访问修饰符 - https://basarat.gitbooks.io/typescript/content/docs/types/readonly.html

interface IModuleMenuItem {
     readonly name : string;
}

class ModuleMenuItem implements IModuleMenuItem {
    public readonly name : string;

    constructor() {
        name = "name";
    }
}

【讨论】:

  • 那么交易是什么?我的意思是它很愚蠢,它破坏了接口的全部意义。
  • @Pachu 对我来说,这就是接口的全部意义所在。它定义了一个实现“符合”的public合约,并且外部组件可以使用而无需关心它是如何实现的。您所追求的是更加强制的实现行为,这是通过大多数语言中的抽象基类来实现的。
  • 有人能告诉 TypeScript 的创建者吗?显然它在定义接口时包括私有成员。 :(
  • @theMayer 不是必需的。您可以使用抽象类来实现接口并创建另一个类来扩展该类。这种实现方法称为复合。尽管您必须使用受保护而不是私有,因为私有无法重新实现。
  • 也添加了答案。还不如有。
【解决方案2】:

我想你可以这样做

interface IModuleMenuItem{
    name: string
}

class ModuleMenuItem implements IModuleMenuItem {
    private _name: string;
    constructor() {
    _name = "name";
    }

    get name(){
    // your implementation to expose name
    }

    set name(value){
    // your implementation to set name         
    }
 }

【讨论】:

  • 我认为这更好,因为我们可以将它与 getter setter 一起使用。公认的解决方案使用getProp(),这也很好,但是 getter setter 使代码更简洁。
  • 这对任何人都有什么作用? this 甚至没有在构造函数中使用。
【解决方案3】:

你可以拥有一个内部状态并为其分配接口而不是类并使该状态私有的唯一方法

class A{
  private state:IA = ...
}

【讨论】:

    【解决方案4】:

    改用抽象类。

    组合优于继承。

    interface AppInterface {
       app: express.Application
       port: string | number
    }
    
    abstract class AbstractApp implements AppInterface {
        app: express.Application
        port: string | number
        constructor(){
            this.app=express()
            this.port=8080
        }
        
        protected defaultMiddlewares(): void {}
    }     
    
    class App extends AbstractApp {
        constructor() {
            super()
        }
    
        protected defaultMiddlewares(): void {
            this.app.use(express.json())
        }
    }
    

    【讨论】:

    【解决方案5】:

    如果类中有私有字段,您需要为该字段引入 setter 和 get 方法,如下所示:

    export class Model {
        private _field: number;
    
        get field(): number {
            return this._field;
        }
    
        set field(value: number) {
            this._field= value;
        }
    }
    

    然后像往常一样创建接口(我们不能对接口字段使用私有修饰符),如下所示:

    export interface IModel {
     field: number;
    }
    

    然后像这样在我们的类中实现它:

    export class Model implements IModel {
    ...
    }
    

    TypeScript 会理解这个模型是正确实现的接口,因为我们已经引入了 set 和 get 方法。

    【讨论】:

      【解决方案6】:

      作为Syntax 回复的附录,不需要包含setter。只需要一个 getter 方法。例如,这可以用于在初始化时设置的只读变量,但我认为在这种情况下最好使用 readonly 修饰符。

      interface IModuleMenuItem
      {
          name: string;
      }
      
      class ModuleMenuItem implements IModuleMenuItem{
          private name$: string;
      
          constructor(name: string)
          {
              this.name$ = name;
          }
      
          public get name()
          {
              return this.name$;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-09-19
        • 2012-12-06
        • 1970-01-01
        • 1970-01-01
        • 2016-08-20
        • 1970-01-01
        • 2017-11-06
        • 2020-01-14
        • 1970-01-01
        相关资源
        最近更新 更多