如何init一个新的类在TS以这样的方式(在c#的例子,以显示我想要的):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
如何init一个新的类在TS以这样的方式(在c#的例子,以显示我想要的):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
当前回答
初始化一个类而不重新声明默认值的所有属性:
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)
}
}
这结合了一些已经很好的答案
其他回答
下面是一个结合了较短的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());
在某些情况下,使用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" }
};
更新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语法被拒绝了)。我更喜欢适当的字段初始化器,但看起来还不会发生。
为了比较,如果你使用强制转换方法,你的初始化器对象必须有你要强制转换的类型的所有字段,加上不要得到任何类本身创建的类特定的函数(或派生)。
我想要一个解决方案,将有以下:
所有数据对象都是必需的,并且必须由构造函数填充。 不需要提供默认值。 可以在类内部使用函数。
我是这样做的:
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的类
这是另一个解决方案:
return {
Field1 : "ASD",
Field2 : "QWE"
} as myClass;