在Typescript中定义构造函数参数和类的实例属性是否有更简洁的方法?

时间:2018-05-09 10:21:51

标签: typescript

目前我正在定义我的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;

这是非常重复的。有没有办法以更干净的方式执行此操作,即使它仅用于接口和实例属性?

3 个答案:

答案 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)

您还可以考虑构建器模式:

1。创建构建器类型和createBuilder util函数:

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

2:在您的班级中使用它:

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

3:使用你的班级:

const me = MyClass.createBuilder()
    .bar("bar")
    .baz(true)
    .foo(3)
    .build();

console.log(me);

问题:

  • 我无法使用私有字段
  • 取决于代理对象

现金: