Typescript -使用类型扩展类

nbnkbykc  于 2023-01-31  发布在  TypeScript
关注(0)|答案(1)|浏览(170)

这里是Typescript新手。假设我有一个来自库的类型,如下所示:

type FooType {
  name: string;
  // Has much more attributes in real life
}

现在我想定义一个名为Foo的类,如下所示:

import { FooType } from 'my-library';

class Foo {
  constructor(data: FooType) {
    Object.assign(this, data);
  }
}

使用这段代码,我可以定义一个foo示例,但是我在自动完成方面遇到了一个问题:

const foo = new Foo({ name: 'foo name' });
// Typing in foo.name does not bring any type information about the "name" attribute

有没有一种方法可以让类自动“继承”类型的所有属性,而不必手动键入它们?

标记为重复后编辑

我想要实现的是避免手动键入类型上已经存在的属性。
感谢@Phil为我提供了一个答案,其中提到这是Typescript中正在发生的问题:https://github.com/microsoft/TypeScript/issues/26792
我现在要做的是:

class Foo {
  constructor(public _data: FooType)
    Object.assign(this, _data);
  }

  get() {
    return this._data;
  }
}

const foo = new Foo({ name: 'Bar' });
foo.get().name; // After typing "foo.get()" the autocomplete works properly.
cbwuti44

cbwuti441#

正如评论中所指出的,Object.assign和TypeScript有一个已知的问题,但这里有一个不错的解决方案,可以模拟这种行为。
GenericSubClass扩展了一个基类(在本例中为FooType),而不必手动定义所有基类属性和方法。这是使用代理 Package 和工厂方法完成的。创建新示例时,不要直接调用新的GenericSubClass,而是使用静态工厂方法GenericSubClass.new({ ... }),该方法将返回带有代理 Package 的GenericSubClass。
在获取属性时,代理子类将首先搜索GenericSubClass,如果没有找到,则将搜索_parent(在本例中为FooType)。
设置属性时,代理的子类将首先检查GenericSubClass上是否存在该属性,如果存在,则将设置该属性,否则将检查_parent并尝试设置该属性。

interface FooType {
  name: string
  greet(): void
}

class GenericSubClass {
  _parent: FooType

  constructor(data: FooType) {
    this._parent = data
  }
  // class method which returns a new instance of MyClass wrapped in a proxy
  // that will get & set properties directly to the data property, then we
  // return the proxied class casted to both MyClass & FooType
  static new(data: FooType) {
    const newClassInstance = new GenericSubClass(data)
    const newProxyInstance = new Proxy(newClassInstance, {
      get(target, prop) {
        if ((target as any)[prop]) return (target as any)[prop]
        if ((target._parent as any)[prop]) return (target._parent as any)[prop]
      },
      set(target, prop, newValue) {
        if ((target as any)[prop]) {
          (target as any)[prop] = newValue
          return true
        }
        if ((target._parent as any)[prop]) {
          (target._parent as any)[prop] = newValue
          return true
        }
        return false
      }
    })
    return newProxyInstance as (typeof newProxyInstance) & FooType
  }
}

那么它可以这样使用:

// Exmaple Usage
// Here we have our FooType which we want to extend.
const myFooType: FooType = {
  name: 'Alice',
  greet: () => {
    console.log(`Hello, ${myFooType.name}`)
  }
}

// Instantiating
// We create a new instance of GenericSubClass with the 
// base class set to FooType
const test = GenericSubClass.new(myFooType)

// Getters
console.log(test)
console.log(test.name)
test.greet()

// Setters
test.name = "Bob"
console.log(test.name)
test.greet()

在TypeScriptPlayground上试试吧!

相关问题