【问题标题】:Generic getters and setters of protected properties受保护属性的通用 getter 和 setter
【发布时间】:2018-05-29 13:21:27
【问题描述】:

考虑这个 TypeScript 类,它通过将实现拆分为超类和子类来提供类型检查的通用 getter 和 setter:

class ICompetence {
    protected _id : number | undefined;
    protected name: string | undefined;
}

export default class Competence extends ICompetence {

    set<K extends keyof ICompetence>(key: K, value: ICompetence[K]): void {
        this[key] = value;
    }

    get<K extends keyof ICompetence>(key: K) : ICompetence[K] {
        return this[key];
    }

    constructor() {
        super();
    }
}

类是这样使用的:

let competence = new Competence():    
competence.set("name", "name value text");

但是,然后我收到此错误:

error TS2345: Argument of type '"name"' is not assignable to parameter of type

可以通过从接口类中删除受保护的注解来克服该错误:

class ICompetence {
    _id : number | undefined;
    name: string | undefined;
}

TypeScript 是否提供任何功能来避免在属性受到保护时发生这种错误?

【问题讨论】:

  • Nope.keyof 只会返回公钥,而不是非公钥
  • 这不是错误......既然你想公开地址set,它必须是公开的......competence.set("name", "name value text");

标签: typescript


【解决方案1】:

由于protected 仅在设计时生成错误并且不会在运行时阻止访问,因此您可能会以另一种方式获得类似的行为,方法是隐藏导出类型的相关属性,如下所示:

首先,将父类的属性公开:

class ICompetence {
  _id: number | undefined;
  name: string | undefined;
}

然后正常扩展类,但不要导出它,并将其重命名为_Competence(“真正的”Competence 稍后会出现)

class _Competence extends ICompetence {

  otherProperty: string = "hmm"; // demonstrate you can add other things

  set<K extends keyof ICompetence>(key: K, value: ICompetence[K]): void {
    this[key] = value;
  }

  get<K extends keyof ICompetence>(key: K): ICompetence[K] {
    return this[key];
  }

  constructor() {
    super();
  }
}

现在我们准备Competence。首先,我们定义类型函数Omit,它从一个类型中移除指定的键:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>

然后我们导出一个名为Competence的接口和一个名为Competence的值,它们派生自_Competence,但不暴露ICompetence的属性。当然,它们仍然存在,但类型系统不会暴露它们:

export interface Competence extends Omit<_Competence, keyof ICompetence> { }
export const Competence = _Competence as new () => Competence;

现在在您的消费者代码中,您应该能够执行以下操作:

const competence = new Competence();
competence.name // error at compile time
competence.otherProperty // okay
const name = competence.get("name") // string or undefined

而且它有效。希望有帮助。祝你好运!

【讨论】:

  • 非常感谢 - 它有效!我不得不将我的 TypeScript 升级到 2.8 版。我必须仔细阅读文档才能理解它为什么起作用。 TypeScript 泛型可以做的事情真是太棒了。
【解决方案2】:

我按照 jcalz 的回答中的想法,但稍微简化了解决方案:

class ICompetence { ... }

export class Competence extends ICompetence { ... }

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>
export interface Competence extends Omit<Competence, keyof ICompetence> { }

然后,该解决方案支持隐藏客户端以访问放置在 ICompetence 类中的属性,而客户端仍然可以访问放置在子类 Competence 中的任何属性。

【讨论】:

    猜你喜欢
    • 2013-07-08
    • 2021-12-02
    • 2018-03-17
    • 1970-01-01
    • 2011-03-11
    • 2011-06-06
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    相关资源
    最近更新 更多