如何init一个新的类在TS以这样的方式(在c#的例子,以显示我想要的):

// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ...  some code after

当前回答

如果要创建新实例时没有设置初始值

1-你必须使用类而不是接口

2-你必须在创建类时设置初始值

export class IStudentDTO {
 Id:        number = 0;
 Name:      string = '';


student: IStudentDTO = new IStudentDTO();

其他回答

我更倾向于这样做,使用(可选的)自动属性和默认值。您没有建议这两个字段是数据结构的一部分,所以这就是我选择这种方式的原因。

您可以在类中拥有属性,然后以通常的方式分配它们。显然,他们可能需要,也可能不需要,所以这也是另一回事。只是这是一个很好的语法糖。

class MyClass{
    constructor(public Field1:string = "", public Field2:string = "")
    {
        // other constructor stuff
    }
}

var myClass = new MyClass("ASD", "QWE");
alert(myClass.Field1); // voila! statement completion on these properties

下面是一个结合了较短的Object应用程序的解决方案。赋值来更紧密地模拟原始的c#模式。

但首先,让我们回顾一下到目前为止提供的技术,包括:

复制接受对象的构造函数,并将其应用于object .assign 复制构造函数中的一个聪明的Partial<T>技巧 针对POJO使用“强制转换” 利用对象。create而不是Object.assign

当然,每种方法都有其优点和缺点。修改目标类以创建复制构造函数可能并不总是一种选择。而“强制转换”会丢失与目标类型相关的所有函数。对象。Create似乎不那么吸引人,因为它需要相当冗长的属性描述符映射。

简短、通用的回答

因此,这里还有另一种更简单的方法,它维护了类型定义和相关的函数原型,并更紧密地模拟了预期的c#模式:

const john = Object.assign( new Person(), {
    name: "John",
    age: 29,
    address: "Earth"
});

就是这样。在c#模式上唯一增加的是Object。赋值时加上2个括号和一个逗号。查看下面的工作示例,确认它维护了类型的函数原型。不需要构造函数,也不需要巧妙的技巧。

工作示例

这个例子展示了如何使用近似c#字段初始化器来初始化一个对象:

人物{ 名称:string = "; 地址:string = "; 年龄:0; aboutMe () { 返回' Hi, I'm ${this.name}, age ${this.name。年龄}和来自${this.address} '; } } // typescript字段初始化式(维护"type"定义) const john =对象。assign(new Person(), { 名称:“约翰”, 年龄:29岁 地址:“地球” }); //初始化对象维护aboutMe()函数原型 console.log(john.aboutMe());

这是我找到的最好的解决办法。

声明一个可以用作装饰器的函数。我称之为自动反射

export function AutoReflect<T extends { new(...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor {
    constructor(...args: any[]) {
      super(args)
      if (typeof args[0] === 'object') {
        Object.assign(this, args[0]);
      }
    }
  };
}

这样做的目的是在构造函数中期望一个对象,并将成员分配给类实例。 在类声明中使用这个

interface IPerson {
  name: string;
  age: number;
}

@AutoReflect
class Person implements IPerson {
  name: string;
  number: number;
  constructor(model?: Partial<IPerson>){}
}

在模型的构造函数中,您可以使模型成为可选的,并且在使用Partial时,您可以在不设置所有属性值的情况下新建实例

new Person({
   name: 'Santa'
});

这个方法创建了一个您想要的类的新实例,并且对它有c#对象初始化的感觉。

我想要一个解决方案,将有以下:

所有数据对象都是必需的,并且必须由构造函数填充。 不需要提供默认值。 可以在类内部使用函数。

我是这样做的:

export class Person {
  id!: number;
  firstName!: string;
  lastName!: string;

  getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }

  constructor(data: OnlyData<Person>) {
    Object.assign(this, data);
  }
}

const person = new Person({ id: 5, firstName: "John", lastName: "Doe" });
person.getFullName();

构造函数中的所有属性都是强制性的,如果省略这些属性将会导致编译器错误。

它依赖于OnlyData从必需的属性中过滤出getFullName(),它的定义如下:

// based on : https://medium.com/dailyjs/typescript-create-a-condition-based-subset-types-9d902cea5b8c
type FilterFlags<Base, Condition> = { [Key in keyof Base]: Base[Key] extends Condition ? never : Key };
type AllowedNames<Base, Condition> = FilterFlags<Base, Condition>[keyof Base];
type SubType<Base, Condition> = Pick<Base, AllowedNames<Base, Condition>>;
type OnlyData<T> = SubType<T, (_: any) => any>;

目前这种方式的局限性:

需要TypeScript 2.8 具有getter /setter的类

可以影响类类型中强制转换的匿名对象。 奖励:在visual studio中,你可以这样受益于智能感知:)

var anInstance: AClass = <AClass> {
    Property1: "Value",
    Property2: "Value",
    PropertyBoolean: true,
    PropertyNumber: 1
};

编辑:

警告:如果类有方法,类的实例将得不到它们。如果AClass有构造函数,它将不会被执行。如果使用instanceof AClass,则会得到false。

总之,应该使用接口而不是类。 最常见的用途是声明为普通旧对象的域模型。 实际上,对于域模型,您应该更好地使用接口而不是类。接口在编译时用于类型检查,与类不同,接口在编译期间被完全删除。

interface IModel {
   Property1: string;
   Property2: string;
   PropertyBoolean: boolean;
   PropertyNumber: number;
}

var anObject: IModel = {
     Property1: "Value",
     Property2: "Value",
     PropertyBoolean: true,
     PropertyNumber: 1
 };