目前我正在定义我的Typescript类的构造函数args和实例属性,如下所示:
$sub_array = array();
foreach($result as $row)
{
$edit = '<button type="button" name="update" id="'.$row["staff_id"].'" class="btn btn-warning btn-xs update">Update</button>';
$delete = '<button type="button" name="delete" id="'.$row["staff_id"].'" class="btn btn-danger btn-xs delete" data-status="'.$row["category_status"].'">Delete</button>';
$sub_array[] = array(
$row['staff_id'],
$row['staff_name'],
$row['staff_identityno'],
$row['staff_address'],
$row['staff_phoneno'],
$edit,
$delete
);
}
$data = $sub_array;
这是非常重复的。有没有办法以更干净的方式执行此操作,即使它仅用于接口和实例属性?
答案 0 :(得分:1)
使用映射类型和条件类型,我们可以创建一个包含类的所有字段的类型,并将其用作构造函数参数。我们也可以使用Object.assign
复制属性,而不是分配每个字段:
type NotMethods<T> = { [P in keyof T]: T[P] extends (...args: any[]) => any ? never: P }[keyof T];
type Fields<T> = { [P in NotMethods<T>]: T[P] }
class MyClass {
foo: number;
bar: string;
baz: boolean;
constructor(props: Fields<MyClass>) {
Object.assign(this, props)
}
method() {
}
}
new MyClass({
foo: 1,
bar: '',
baz: true
});
游乐场link
Fields
类型可以重用于任何类。构造函数参数中将需要该类的所有字段。
或者,如果您有可选字段并使用严格空检查,则可以编写一个版本,以保留构造函数参数中字段的可选性:
type NotMethods<T> = Exclude<{ [P in keyof T]: T[P] extends (...args: any[]) => any ? never: P }[keyof T], undefined>;
type FilterUndefined<T, TKeys extends keyof T = keyof T> = Exclude<{ [P in TKeys]: undefined extends T[P] ? never: P }[TKeys], undefined>;
type KeepUndefined<T, TKeys extends keyof T = keyof T> = Exclude<TKeys, FilterUndefined<T, TKeys> | undefined>
type Fields<T> = { [P in FilterUndefined<T, NotMethods<T>>]: T[P] } & { [P in KeepUndefined<T, NotMethods<T>>]?: T[P] }
class MyClass {
foo: number;
bar: string;
baz?: boolean;
constructor(props: Fields<MyClass>) {
Object.assign(this, props)
props.foo
}
method() {
}
}
new MyClass({
foo: 1,
bar: '',
baz: true
});
new MyClass({
foo: 1,
bar: '',
});
游乐场link
答案 1 :(得分:0)
这可能不适用于所有情况,但这会编译:
class MyClass {
foo: number;
bar: string;
baz: boolean;
constructor (props: MyClass) {
this.foo = props.foo;
this.bar = props.bar;
this.baz = props.baz;
}
}
const props = {
foo: 1,
bar: "s",
baz: true
};
const x = new MyClass(props);
答案 2 :(得分:0)
您还可以考虑构建器模式:
type Builder<T> = {
[k in keyof T]: (arg: T[k]) => Builder<T>
} & { build(): T }
function createBuilder<T>(type: { new(...args: any[]) : T}): Builder<T> {
var built: any = {};
var builder = new Proxy({}, {
get: function(target, prop, receiver) {
if (prop === 'build') {
return () => new type(built);
}
return (x: any): any => {
built[prop] = x;
return builder;
}
}
});
return builder as any;
}
class MyClass {
foo: number;
bar: string;
baz: boolean;
public static createBuilder(): Builder<MyClass> {
return createBuilder<MyClass>(MyClass);
}
constructor (builder: Builder<MyClass>) {
Object.assign(this, builder);
}
}
const me = MyClass.createBuilder()
.bar("bar")
.baz(true)
.foo(3)
.build();
console.log(me);