如何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
当前回答
我建议一种不需要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();
重点:
Typescript 2.1不需要,Partial<T>不需要 它支持函数(与不支持函数的简单类型断言相比)
其他回答
如果你使用的是旧版本的typescript < 2.1,那么你可以使用类似于下面的方法,基本上是将任意类型转换为类型化对象:
const typedProduct = <Product>{
code: <string>product.sku
};
注意:使用此方法只适用于数据模型,因为它将删除 对象中的所有方法。它基本上是将任何对象转换为a 类型的对象
最简单的方法是使用类型强制转换。
return <MyClass>{ Field1: "ASD", Field2: "QWE" };
可以有一个带有可选字段(用?标记)的类和一个接收同一类实例的构造函数。
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);
}
问题是所有字段都是可选的,在大多数情况下都不可取。
我想要一个解决方案,将有以下:
所有数据对象都是必需的,并且必须由构造函数填充。 不需要提供默认值。 可以在类内部使用函数。
我是这样做的:
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的类
更新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语法被拒绝了)。我更喜欢适当的字段初始化器,但看起来还不会发生。
为了比较,如果你使用强制转换方法,你的初始化器对象必须有你要强制转换的类型的所有字段,加上不要得到任何类本身创建的类特定的函数(或派生)。