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

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

当前回答

更新07/12/2016: Typescript 2.1引入了映射类型,并提供了Partial<T>,这允许您这样做....

class Person {
    public name: string = "default"
    public address: string = "default"
    public age: number = 0;

    public constructor(init?:Partial<Person>) {
        Object.assign(this, init);
    }
}

let persons = [
    new Person(),
    new Person({}),
    new Person({name:"John"}),
    new Person({address:"Earth"}),    
    new Person({age:20, address:"Earth", name:"John"}),
];

最初的回答:

我的方法是定义一个单独的fields变量,然后传递给构造函数。诀窍是将这个初始化式的所有类字段重新定义为可选的。创建对象时(使用默认值),只需将初始化器对象赋值给this;

export class Person {
    public name: string = "default"
    public address: string = "default"
    public age: number = 0;

    public constructor(
        fields?: {
            name?: string,
            address?: string,
            age?: number
        }) {
        if (fields) Object.assign(this, fields);
    }
}

或者手动操作(更安全):

if (fields) {
    this.name = fields.name || this.name;       
    this.address = fields.address || this.address;        
    this.age = fields.age || this.age;        
}

用法:

let persons = [
    new Person(),
    new Person({name:"Joe"}),
    new Person({
        name:"Joe",
        address:"planet Earth"
    }),
    new Person({
        age:5,               
        address:"planet Earth",
        name:"Joe"
    }),
    new Person(new Person({name:"Joe"})) //shallow clone
]; 

控制台输出:

Person { name: 'default', address: 'default', age: 0 }
Person { name: 'Joe', address: 'default', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 5 }
Person { name: 'Joe', address: 'default', age: 0 }   

这为您提供了基本的安全和属性初始化,但这都是可选的,并且可能是无序的。如果不传递字段,则保留类的默认值。

您还可以将其与所需的构造函数参数混合使用——将字段放在末尾。

我认为这和c#风格差不多(实际的field-init语法被拒绝了)。我更喜欢适当的字段初始化器,但看起来还不会发生。

为了比较,如果你使用强制转换方法,你的初始化器对象必须有你要强制转换的类型的所有字段,加上不要得到任何类本身创建的类特定的函数(或派生)。

其他回答

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

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

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

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


student: IStudentDTO = new IStudentDTO();
type ExcludeMethods<T> = Pick<T, { [K in keyof T]: T[K] extends Function ? never : K }[keyof T]>;

class Person{
  name: string = "N/A";
  age: number = 0;
  gender?: "male" | "female"

  constructor(init?:ExcludeMethods<Person>){
    Object.assign(this, init);
  }

  Describe(){return `${this.name} ${this.age} ${this.gender ?? ""}` }
}

var p1 = new Person();
var p2 = new Person({
  name: "John",
  age: 20
});
var p3 = new Person({
  name: "Mary",
  age: 25,
  gender: "female"
});

console.log(p1.Describe()) // N/A 0
console.log(p2.Describe()) // John 20
console.log(p3.Describe()) // Mary 25 female

可以有一个带有可选字段(用?标记)的类和一个接收同一类实例的构造函数。

class Person {
    name: string;     // required
    address?: string; // optional
    age?: number;     // optional

    constructor(person: Person) {
        Object.assign(this, person);
    }
}

let persons = [
    new Person({ name: "John" }),
    new Person({ address: "Earth" }),    
    new Person({ age: 20, address: "Earth", name: "John" }),
];

在这种情况下,您将不能省略必需的字段。这为您提供了对对象构造的细粒度控制。

你可以使用Partial类型的构造函数,如其他答案中所述:

public constructor(init?:Partial<Person>) {
    Object.assign(this, init);
}

问题是所有字段都是可选的,在大多数情况下都不可取。

可以影响类类型中强制转换的匿名对象。 奖励:在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
 };

在某些情况下,使用Object.create可能是可以接受的。如果您需要向后兼容或想要滚动自己的初始化函数,Mozilla引用包含一个polyfill。

应用于你的例子:

Object.create(Person.prototype, {
    'Field1': { value: 'ASD' },
    'Field2': { value: 'QWE' }
});

有用的场景

单元测试 内联声明

在我的案例中,我发现这在单元测试中很有用,原因有二:

在测试期望时,我经常希望创建一个苗条的对象作为期望 单元测试框架(如Jasmine)可能会比较对象原型(__proto__)并使测试失败。例如:

var actual = new MyClass();
actual.field1 = "ASD";
expect({ field1: "ASD" }).toEqual(actual); // fails

单元测试失败的输出不会产生关于不匹配的线索。

在单元测试中,我可以选择我支持的浏览器

最后,http://typescript.codeplex.com/workitem/334上提出的解决方案不支持内联json风格的声明。例如,以下代码不能编译:

var o = { 
  m: MyClass: { Field1:"ASD" }
};