【问题标题】:Typescript automatically get interface properties in a classTypescript 自动获取类中的接口属性
【发布时间】:2023-03-10 03:52:01
【问题描述】:

TypeScript 专家您好。

我有以下代码,但我必须在类中重复接口属性,否则我会得到:

类错误地实现了接口

当使用接口时,是否有一个 TypeScript 简写来执行此操作而无需声明 Id: number; 和类中的所有其他属性?谢谢

interface INavigation {
  Id: number;
  AppId: number;
  NavId: number;
  Name: string;
  ParentId: string;
  PageURL: string;
  Position: string;
  Active: string;
  Desktop: string;
  Tablet: string;
  Phone: string;
  RoleId: string;
  Target: string;
}

class Navigation implements INavigation {

  Id: number;
  AppId: number;
  NavId: number;
  Name: string;
  ParentId: string;
  PageURL: string;
  Position: string;
  Active: string;
  Desktop: string;
  Tablet: string;
  Phone: string;
  RoleId: string;
  Target: string;

  constructor(navigation: any) {
    this.Id = navigation.Id
    this.AppId = navigation.NavAppId
    this.NavId = navigation.NavId
    this.Name = navigation.NavName
    this.ParentId = navigation.NavParentId
    this.PageURL = navigation.NavPageURL
    this.Position = navigation.NavPosition
    this.Active = navigation.NavActive
    this.Desktop = navigation.NavDesktop
    this.Tablet = navigation.NavTablet
    this.Phone = navigation.NavPhone
    this.RoleId = navigation.NavRoleId
    this.Target = navigation.NavTarget
  }
}

【问题讨论】:

  • 虽然下面的答案非常棒,但如果您没有其他类实现相同的接口,则可能根本不需要实现接口

标签: typescript


【解决方案1】:

这现在可以在 Typescript 中使用类/接口合并。

interface Foo {
    a: number;
}

interface Baz extends Foo { }
class Baz {
    constructor() {
        console.log(this.a); // no error here
    }
}

https://github.com/Microsoft/TypeScript/issues/340#issuecomment-184964440

【讨论】:

  • 感谢您的提示。这应该是选择的答案
  • 这确实将接口的所有属性都添加到了类中,但是如何避免构造函数中分配的巨大混乱呢?
  • 鉴于上面的评论,没有我希望的那么有用 - 但比踢裤子 +1 更好
【解决方案2】:

对此没有内置支持。

然而,我们可以使用一个返回类的函数作为我们类的基类型。这个函数可能有点谎言,并声称它实现了接口。如有必要,我们还可以为成员传递一些默认值。

interface INavigation {
  Id: number;
  AppId: number;
  NavId: number;
  Name: string;
  ParentId: string;
  PageURL: string;
  Position: string;
  Active: string;
  Desktop: string;
  Tablet: string;
  Phone: string;
  RoleId: string;
  Target: string;
}

function autoImplement<T>(defaults?: Partial<T>) {
  return class {
    constructor() {
      Object.assign(this, defaults || {});
    }
  } as new () => T
}

class Navigation extends autoImplement<INavigation>() {
  constructor(navigation: any) {
    super();
    // other init here
  }
}

如果我们想要一个基类,事情会变得有点复杂,因为我们必须对基类进行一些手术:

function autoImplementWithBase<TBase extends new (...args: any[]) => any>(base: TBase) {
  return function <T>(defaults?: Partial<T>): Pick<TBase, keyof TBase> & {
    new(...a: (TBase extends new (...o: infer A) => unknown ? A : [])): InstanceType<TBase> & T
  } {
    return class extends base {
      constructor(...a: any[]) {
        super(...a);
        Object.assign(this, defaults || {});
      }
    } as any
  }
}

class BaseClass {
  m() { }
  foo: string
  static staticM() { }
  static staticFoo: string
}

class Navigation extends autoImplementWithBase(BaseClass)<INavigation>() {
  constructor(navigation: any) {
    super();
    // Other init here
  }
}

Navigation.staticFoo
Navigation.staticM
new Navigation(null).m();
new Navigation(null).foo;

【讨论】:

    【解决方案3】:

    两个答案之间的混合,通过在构造函数中使用类/接口合并和 Object.assign 来避免构造函数中的长时间赋值:

    interface Foo {
        a: number;
        b: number;
    }
    
    interface Baz extends Foo { }
    
    class Baz  {
        c: number = 4
    
      constructor (foo: Foo) {
        Object.assign(this, foo, {})
      }
      
      getC() {
        return this.c
      }
    }
    
    let foo: Foo = {
        a: 3,
        b: 8
    }
    
    let baz = new Baz(foo)
    // keep methods and properties
    console.warn(baz)
    

    【讨论】:

      【解决方案4】:

      类声明应显式实现接口。

      【讨论】:

      • 不知道是什么意思,请您提供一个例子或详细说明 - thx
      • 这意味着你应该实现接口中的所有成员
      • 你想说清楚吗?
      • 对不起,我弄错了,是的明确
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 2021-01-18
      • 2020-02-28
      • 1970-01-01
      • 1970-01-01
      • 2022-08-11
      相关资源
      最近更新 更多