首页 > 解决方案 > 为静态方法包含定义类型参数约束

问题描述

如果是序列化程序,我可以定义类型具有特定静态成员/“静态”实现接口的类型参数约束吗?

意义:

function getStuff<T>(...) -> T {
  T.buildFormJson(getStuffJson(...))
}

哪里buildFromJsonfunction(input: Object): T

我可以为 T 定义一个约束,只接受定义了这个静态成员的类型吗?

标签: typescriptgeneric-programming

解决方案


基于:https ://github.com/microsoft/TypeScript/issues/13462#issuecomment-275860898

interface JsonDeserializable<T> {
  fromJson(obj: Object): T;
}
interface JsonSerializable {
  toJson(): Object;
}

用法:

import * as assert from "assert";

class Point2D {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }


  toJson(): Object {
    return this;
  }

  static fromJson(obj: Object): Point3D {
    return new Point3D(obj['x'], obj['y'], obj['z']);
  }
}

class Point3D {
  x: number;
  y: number;
  z: number;

  constructor(x: number, y: number, z: number) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  toJson(): Object {
    return this;
  }

  static fromJson(obj: Object): Point3D {
    return new Point3D(obj['x'], obj['y'], obj['z']);
  }
}


class Baz {
  foo: Point2D;
  bar: Point3D;

  constructor(foo: Point2D, bar: Point3D) {
    this.foo = foo;
    this.bar = bar;
  }

  toJson(): Object {
    return {
      foo: this.foo.toJson(),
      bar: this.bar.toJson()
    }
  }

  static fromJson(obj: Object): Baz {
    return new Baz(Point2D.fromJson(obj['foo']), Point3D.fromJson(obj['bar']));
  }
}



var DATA: Object = {};

function getJson(): Object {
  return DATA;
}

function saveJson(o: Object) {
  DATA = o;
}


// Only accepts T that is serializable
function save<T extends JsonSerializable>(o: T) {
  const json = o.toJson();
  saveJson(json);
}

// Only accepts T that is deserializable
function load<InstanceType>(cls: JsonDeserializable<InstanceType>): InstanceType {
  const data = getJson();

  return cls.fromJson(data);
}

// Only accepts T that is both serializable and deserializable
function testSerde<T extends JsonSerializable>(cls: JsonDeserializable<T>, obj: Object) {
  const instance = cls.fromJson(obj);
  const json = instance.toJson();

  assert.deepEqual(json, obj);
}


const baz = new Baz(new Point2D(1,2), new Point3D(1,2,3));

save(baz);
console.log(load(Baz)); // Baz object
testSerde(Baz, { foo: { x: 1, y: 2 }, bar: {x: 1, y: 2, z: 3}});

推荐阅读