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

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

当前回答

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

其他回答

最简单的方法是使用类型强制转换。

return <MyClass>{ Field1: "ASD", Field2: "QWE" };

初始化一个类而不重新声明默认值的所有属性:

class MyClass{ 
  prop1!: string  //required to be passed in
  prop2!: string  //required to be passed in
  prop3 = 'some default'
  prop4 = 123

  constructor(opts:{prop1:string, prop2:string} & Partial<MyClass>){
    Object.assign(this,opts)
  }
}

这结合了一些已经很好的答案

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

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);
}

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

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

class MyClass {
  public name!: string;
  public age!: number;
  public optional?: boolean;
  private yep: string = "";

  constructor(props: ExcludeMethods<typeof MyClass.prototype>) {
    Object.assign(this, props);
  }

  public method() {
  }
}

const thing = new MyClass({
  name: "bob",
  age: 15
});

TS操场

这里有一个解决方案:

不强迫你让所有字段都是可选的(不像Partial<…>) 区分类方法和函数类型的字段(不同于OnlyData<…>解决方案) 通过定义Params接口提供了一个很好的结构 不需要重复变量名和类型不止一次

唯一的缺点是一开始看起来比较复杂。


// Define all fields here
interface PersonParams {
  id: string
  name?: string
  coolCallback: () => string
}

// extend the params interface with an interface that has
// the same class name as the target class
// (if you omit the Params interface, you will have to redeclare
// all variables in the Person class)
interface Person extends PersonParams { }

// merge the Person interface with Person class (no need to repeat params)
// person will have all fields of PersonParams
// (yes, this is valid TS)
class Person {
  constructor(params: PersonParams) {
    // could also do Object.assign(this, params);

    this.id = params.id;
    this.name = params.name;

    // intellisence will expect params
    // to have `coolCallback` but not `sayHello`
    this.coolCallback = params.coolCallback;
  }

  // compatible with functions
  sayHello() {
    console.log(`Hi ${this.name}!`);
  }
}

// you can only export on another line (not `export default class...`)
export default Person;