Nic*_*kon 196 typescript
如何以TS这种方式初始化一个新类(例如C#显示我想要的东西):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
Run Code Online (Sandbox Code Playgroud)
解决方案:
经典TS语法:
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
Run Code Online (Sandbox Code Playgroud)
Mei*_*hes 384
更新时间07/12/2016:
Typescript 2.1引入了Mapped Types并提供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"}),
];
Run Code Online (Sandbox Code Playgroud)
原答案:
我的方法是定义一个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);
}
}
Run Code Online (Sandbox Code Playgroud)
或者手动完成(更安全一点):
if (fields) {
this.name = fields.name || this.name;
this.address = fields.address || this.address;
this.age = fields.age || this.age;
}
Run Code Online (Sandbox Code Playgroud)
用法:
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
];
Run Code Online (Sandbox Code Playgroud)
和控制台输出:
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 }
Run Code Online (Sandbox Code Playgroud)
这为您提供了基本的安全性和属性初始化,但它全部是可选的,可以是无序的.如果不传递字段,则单独保留类的默认值.
您也可以将它与所需的构造函数参数混合 - 坚持fields到最后.
关于接近C#样式我认为(实际的field-init语法被拒绝).我更喜欢适当的字段初始化,但看起来还不会发生.
为了进行比较,如果使用强制转换方法,则初始化对象必须包含要转换为的类型的所有字段,并且不要获取由类本身创建的任何特定于类的函数(或派生).
Wou*_*ort 73
TypeScript codeplex上存在一个描述此问题的问题:支持对象初始值设定项.
如上所述,您可以通过在TypeScript中使用接口而不是类来实现此目的:
interface Name {
first: string;
last: string;
}
class Person {
name: Name;
age: number;
}
var bob: Person = {
name: {
first: "Bob",
last: "Smith",
},
age: 35,
};
Run Code Online (Sandbox Code Playgroud)
Jon*_* B. 21
下面是一个解决方案,它结合了更短的应用程序,Object.assign以更接近地模拟原始C#模式.
但首先,让我们回顾一下到目前为止提供的技术,包括:
Object.assignPartial<T>复制构造函数中的一个聪明技巧Object.create而不是Object.assign当然,每个人都有自己的优缺点.修改目标类以创建复制构造函数可能并不总是一个选项.并且"强制转换"会丢失与目标类型相关的任何功能. Object.create似乎不太吸引人,因为它需要一个相当冗长的属性描述符映射.
所以,这是另一种更简单的方法,维护类型定义和相关的函数原型,并更紧密地模拟预期的C#模式:
const john = Object.assign( new Person(), {
name: "John",
age: 29,
address: "Earth"
});
Run Code Online (Sandbox Code Playgroud)
而已.C#模式上唯一的补充是Object.assign2个括号和逗号.查看下面的工作示例,确认它维护了类型的函数原型.不需要构造函数,也没有聪明的技巧.
此示例显示如何使用C#字段初始值设定项的近似值初始化对象:
class Person {
name: string = '';
address: string = '';
age: number = 0;
aboutMe() {
return `Hi, I'm ${this.name}, aged ${this.age} and from ${this.address}`;
}
}
// typescript field initializer (maintains "type" definition)
const john = Object.assign( new Person(), {
name: "John",
age: 29,
address: "Earth"
});
// initialized object maintains aboutMe() function prototype
console.log( john.aboutMe() );Run Code Online (Sandbox Code Playgroud)
rdh*_*aut 20
您可以影响在类类型中输入的匿名对象. 额外奖励:在视觉工作室中,你可以通过这种方式受益于intellisense :)
var anInstance: AClass = <AClass> {
Property1: "Value",
Property2: "Value",
PropertyBoolean: true,
PropertyNumber: 1
};
Run Code Online (Sandbox Code Playgroud)
编辑:
警告如果类有方法,则类的实例将不会获取它们,并且不会执行构造函数.
此解决方案应仅用于接口.例如,使用此解决方案将模型存储为Plain Old Object.
interface IModel {
Property1: string;
Property2: string;
PropertyBoolean: boolean;
PropertyNumber: number;
}
var anObject: IModel = {
Property1: "Value",
Property2: "Value",
PropertyBoolean: true,
PropertyNumber: 1
};
Run Code Online (Sandbox Code Playgroud)
Veg*_*ter 13
我建议一种不需要Typescript 2.1的方法:
class Person {
public name: string;
public address?: string;
public age: number;
public constructor(init:Person) {
Object.assign(this, init);
}
public someFunc() {
// todo
}
}
let person = new Person(<Person>{ age:20, name:"John" });
person.someFunc();
Run Code Online (Sandbox Code Playgroud)
关键点:
Partial<T>不是必需的小智 13
您可以拥有一个带有可选字段(用 ? 标记)的类和一个接收同一类实例的构造函数。
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" }),
];
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将无法省略必填字段。这使您可以对对象构造进行细粒度控制。
您可以使用具有 Partial 类型的构造函数,如其他答案中所述:
public constructor(init?:Partial<Person>) {
Object.assign(this, init);
}
Run Code Online (Sandbox Code Playgroud)
问题是所有字段都变成可选的,并且在大多数情况下是不可取的。
Vit*_*lyB 12
我想要一个具有以下内容的解决方案:
这是我这样做的方式:
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();
Run Code Online (Sandbox Code Playgroud)
构造函数中的所有属性都是强制性的,如果没有编译器错误,则不能省略。
它取决于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>;
Run Code Online (Sandbox Code Playgroud)
这种方式的当前限制:
Ral*_*lle 11
我更倾向于这样做,使用(可选)自动属性和默认值.您没有建议这两个字段是数据结构的一部分,所以这就是我选择这种方式的原因.
您可以在类上拥有属性,然后以通常的方式分配它们.显然它们可能需要也可能不需要,所以这也是其他的东西.只是这是一个很好的语法糖.
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
Run Code Online (Sandbox Code Playgroud)
Jac*_*hee 11
在某些情况下,使用它是可以接受的Object.create.如果您需要反向兼容性或想要滚动自己的初始化函数,Mozilla引用包括polyfill.
适用于您的示例:
Object.create(Person.prototype, {
'Field1': { value: 'ASD' },
'Field2': { value: 'QWE' }
});
Run Code Online (Sandbox Code Playgroud)
在我的情况下,我发现这在单元测试中很有用,原因有两个:
__proto__)并且不通过测试.例如:var actual = new MyClass();
actual.field1 = "ASD";
expect({ field1: "ASD" }).toEqual(actual); // fails
Run Code Online (Sandbox Code Playgroud)
单元测试失败的输出不会产生关于不匹配的线索.
最后,http://typescript.codeplex.com/workitem/334上提出的解决方案不支持内联json样式声明.例如,以下内容无法编译:
var o = {
m: MyClass: { Field1:"ASD" }
};
Run Code Online (Sandbox Code Playgroud)
小智 5
要初始化一个类而不重新声明所有默认属性:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
这结合了一些已经很优秀的答案
| 归档时间: |
|
| 查看次数: |
172378 次 |
| 最近记录: |