typescript 创建具有未知属性的类

j2qf4p5b  于 2023-03-13  发布在  TypeScript
关注(0)|答案(3)|浏览(177)

我希望创建一个具有未知属性的类。基本上,我将一个对象传递给它的构造函数,它使用该对象的属性。这在JavaScript中很容易,但在TypeScript中似乎很痛苦。
我希望为特定对象添加 * 几个 * 方法,而不是全部--或者像下面这样的简写(只是一个例子):

function toString() {
  return JSON.stringify(this).replace(
    /[\u007f-\uffff]/g,
    (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
  );
}

const obj = { pencil: '✎' };

Object.definePropery(
  obj,
  'toString',
  { value: toString.bind(obj) }
);

console.log(`${obj}`); // {"pencil":"\u270e"}

这仅仅是一个例子,但是我如何创建一个类,它可以简单地(仅仅是一个例子):

class MyClass {
  constructor(/*...*/) {
    // ...
  }

  toString() {
    return JSON.stringify(this).replace(
      /[\u007f-\uffff]/g,
      (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
    );
  }

  anotherMethod() {
    // ...
  }

  yetAnotherOne() {
    // ...
  }
}

const myClass1 = new MyClass({ hello: 'world' });
console.log(myClass1.hello); // world
console.log(`JSON: ${myClass1}`); // {"hello":"world"}
console.log(myClass1.anotherMethod());

const myClass2 = new MyClass({ foo: 'bar' });
console.log(myClass2.foo); // bar
console.log(myClass2.yetAnotherOne());

也许我把事情复杂化了,但任何帮助都是感激的。
谢谢!

e4yzc0pl

e4yzc0pl1#

你可以在JS中做的任何事情你也可以在TS中做,所以这是可能的。然而,这完全违背了TypeScript的本意,所以写起来有点烦人。你只需要在任何时候访问MyClass对象时将其转换为具有适当字段的类型。最方便的是any。否则,你必须先通过unknown

class MyClass {
  constructor(obj: any) {
    for (const prop in obj) {
      (this as any)[prop] = obj[prop];
    }
  }

  toString() {
    return JSON.stringify(this).replace(
      /[\u007f-\uffff]/g,
      (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
    );
  }

  anotherMethod() {
    // ...
  }

  yetAnotherOne() {
    // ...
  }
}

const myClass1 = new MyClass({ hello: 'world' });
// casting to any:
console.log((myClass1 as any).hello); // world
console.log(`JSON: ${myClass1}`); // {"hello":"world"}
console.log(myClass1.anotherMethod());

const myClass2 = new MyClass({ foo: 'bar' });
// casting to { foo: string } via unknown:
console.log((myClass2 as unknown as { foo: string }).foo); // bar
console.log(myClass2.yetAnotherOne());

我不明白你为什么要这么做,但你说对了。

wb1gzix0

wb1gzix02#

我找到了一种方法来最小化“as any”类型转换的数量(通过利用如何使用接口来缩小类的类型):

interface MyClass {
  [key: string]: any;
}

class MyClass {
  constructor(obj: any) {
    for (const prop in obj) {
      this[prop] = obj[prop];
    }
  }

  toString() {
    return JSON.stringify(this).replace(
      /[\u007f-\uffff]/g,
      (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
    );
  }

  anotherMethod() {
    // ...
  }

  yetAnotherOne() {
    // ...
  }
}

const myClass1 = new MyClass({ hello: 'world' });
console.log(myClass1.hello); // world 
console.log(`JSON: ${myClass1}`); // {"hello":"world"}
console.log(myClass1.anotherMethod());

const myClass2 = new MyClass({ foo: 'bar' });
console.log(myClass2.foo); // bar
console.log(myClass2.yetAnotherOne());

例如,如果您确切地知道值的类型,则可能会有所改进

interface MyClass {
  [key: string]: string | ((...args: any[]) => any); 
}

((...args: any[]) => any)部分用于匹配anotherMethod()等函数

编辑:

找到了一种更简单的方法,可以直接在类定义中添加[key: string]: any

class MyClass {
  [key: string]: any;
  constructor(obj: any) {
    for (const prop in obj) {
      this[prop] = obj[prop];
    }
  }

  toString() {
    return JSON.stringify(this).replace(
      /[\u007f-\uffff]/g,
      (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
    );
  }

  anotherMethod() {
    // ...
  }

  yetAnotherOne() {
    // ...
  }
}

Playground链接

23c0lvtd

23c0lvtd3#

据我所知,您最好像往常一样使用对象并添加属性:

const obj = {pencil: '✎'}
if(condition) obj['lock'] = 🔒

你也可以按照isaactfa说的去做,但是你肯定会把事情弄得过于复杂

相关问题