【问题标题】:Is there a better shorthand for Typescript class/interface definitions?Typescript 类/接口定义有更好的简写吗?
【发布时间】:2021-12-09 01:06:02
【问题描述】:

我正在定义一个 typescript 类,其构造函数参数由接口定义,它将属性限制为仅定义的属性

以下代码 sn-p 可以按预期工作,但是,有没有办法减少代码以使其不那么重复?每个属性都提到了4次,一定有更好的办法。

interface MyInterface {
  property1: string;
  property2: boolean;
  property3: number;
}
class MyClass {
  property1: string;
  property2: boolean;
  property3: number;
  constructor(parameters: MyInterface) {
    this.property1 = parameters.property1;
    this.property2 = parameters.property2;
    this.property3 = parameters.property3;
  }
}

const example = new MyClass({property1: "Property 1", property2: true, property3: 3, extraProperty: "Shouldn't exist"});
console.log(example);

编辑:我还需要在运行时限制具有其他未知属性的对象的属性。

【问题讨论】:

  • 我认为您遇到的问题是您的示例不应该编译。您将收到类型错误,因为MyInterface 没有属性extraProperty。我假设这个对象来自一个外部 API,所以你不能确定它会有什么属性?
  • @GeraintAnderson 这就是我希望解决的问题。我需要从 api 中获取一个对象并删除其他未定义的属性
  • 啊,这是重要的信息。 TypeScript 已经在编译时尽可能地限制了属性。但是,如果您需要在运行时使用来自 API 的数据检查它们,那么您需要在代码中进行实际检查,例如if (hasExtraProperties(...)) { throw Error(...) }
  • 或者实际上您可能只想忽略额外的属性而不是抛出错误。所以也许只是for (const key in parameters) { if (this.hasOwnProperty(key)) { this[key] = parameters[key] } }
  • 在运行时需要["property1", "property2", "property3"] 形式的键列表才能执行此操作。像this approach 这样的东西对你有用吗?或者this one?如果是这样,我可以写一个答案供您选择;如果不能,您能否详细说明问题,我可以看看它是否可以解决?

标签: typescript class shorthand


【解决方案1】:

怎么样?

interface MyInterface {
    property1: string;
    property2: boolean;
    property3: number;
}

class MyClass implements MyInterface {
    property1: string;
    property2: boolean;
    property3: number;

    constructor(parameters: MyInterface) {
        Object.assign(this, parameters);
    }
}

【讨论】:

  • 请注意,如果您启用了 TS strict 选项,则需要在每个属性声明中添加 ! 以防止编译错误(因此 property1!: string 等)
  • 此解决方案缺少将属性限制为仅定义的属性的能力。 IE。 extraProperty:“不应该存在”将包含在属性中,但不应该
  • 实际上由于parameters: MyInterface,它仍然在限制它。试一试,你会发现它不会让你通过extraProperty
  • 没错,但是,当我从属性未知的外部 API 传入对象时,它会返回额外的属性
【解决方案2】:

我相信这将是最简洁的方式,但不一定是最好的。这取决于您的用例——特别是构造函数中的 parameters 是否始终与您的类的声明属性匹配。如果不是,那么你会想要坚持使用界面(而且使用界面可能更干净)。

class MyClass {
    property1!: string
    property2!: boolean
    property3!: number

    constructor(parameters: typeof MyClass.prototype) {
        Object.assign(this, parameters)
    }
}

【讨论】:

    【解决方案3】:
    interface MyInterface {
      property1: string;
      property2: boolean;
      property3: number;
    }
    
    class MyClass implements MyInterface {
      constructor(
        public property1: string,
        public property2: boolean,
        public property3: number
      ) { }
    }
    
    const example = new MyClass("Property 1", true, 3, "Shouldn't exist");
    console.log(example);
    

    通过将public 放入构造函数参数中,我不需要在构造函数之外声明它们。 MyClass 实现了MyInterface,所以我知道我已经在MyClass 中声明了我需要的所有属性。

    也许这并不真正适用于您的需求,因为您必须在构造函数中手动分配每个属性,但它可能会让您有所考虑。

    【讨论】:

      【解决方案4】:

      是的,这是可能的,但是您需要在 parameters 属性中添加故事类参数:

      interface MyInterface {
        property1: string;
        property2: boolean;
        property3: number;
      }
      class MyClass {
        constructor(public parameters: MyInterface) {  }
      }
      
      const example = new MyClass({ property1: "Property 1", property2: true, property3: 3, extraProperty: "Shouldn't exist" });
      console.log(example);
      
      example.parameters.property1 // ok
      

      Playground

      请看我在constructor中添加的public关键字

      如果您想在运行时验证您的对象,您应该使用user-defined-type-guardsio-ts

      TypeScript 有静态类型系统

      【讨论】:

      • 我猜 OP 不希望将所有属性都放在一个 parameters 属性中。所以它更像constructor(public property1: string, public property2: boolean, ...。缺点是您仍然必须在构造函数中手动分配每个属性。
      • 如果你在构造函数中使用public,你不需要分配它。你只是把它分配给它自己。
      • @ShamPooSham 是的,所以它可能只是constructor(public parameters: MyInterface) { }(空的构造函数主体)。但如果你想将parameters 对象作为输入并将其分配给单独的属性(this.property1 等),你仍然需要进行分配。
      • @ShamPooSham 你是对的
      • 此解决方案缺少将属性限制为仅定义的属性的能力。 IE。 extraProperty:“不应该存在”将包含在属性中,但不应该
      猜你喜欢
      • 2015-07-27
      • 1970-01-01
      • 1970-01-01
      • 2016-10-27
      • 1970-01-01
      • 2021-04-19
      • 2020-11-24
      • 1970-01-01
      相关资源
      最近更新 更多