如何从 Typescript 中的类属性(省略方法)派生接口?

Sep*_*eed 3 typescript typescript-typings

我有一些包含所有公共成员(本质上是一个结构)的类,我想存储它的数据:

class SomeClass {
  public foo: string;
  public bar: string;

  public getFooBar() { 
    return this.foo + this.bar;
  }
}
Run Code Online (Sandbox Code Playgroud)

作为存储检索的一部分,我希望有一个正确定义它的接口,例如:

interface ISomeClassData {
  foo: string;
  bar: string;
  // notice there is no getFooBar()
}

const test: ISomeClassData = magic();
if ("getFooBar" in test === false) {
  return "Success.  This is an interface, and not a class";
}
Run Code Online (Sandbox Code Playgroud)

做这种事情的一种典型(但不适用)的方式如下:

interface ISomeClassData {
  foo: string;
  bar: string;
}

class SomeClass extends ISomeClassData {
  // code omitted
}
Run Code Online (Sandbox Code Playgroud)

在我的场景中,类中公共属性的数量非常大,并且将某些内容添加到类中而不添加到接口中将非常非常容易。相反,我想做的是从类派生接口。

是否可以从 Typescript 中的类属性(省略方法)派生接口?


想象的例子:

type ISomeClassData = JustThePublicProperties<SomeClass>
Run Code Online (Sandbox Code Playgroud)

Ale*_*yne 7

听起来您想要所有不是函数的键,并且您想仅用这些键构建一个对象。

// Get the keys that are not functions. We consider these data.
type ClassDataKeys<T> = {

  // Iterate over each property.
  [K in keyof T]:

    // If the property is a function...
    T[K] extends (...args: any[]) => any

    // Functions are not allowed, use never to exclude it.
    ? never

    // Not a function, it is data, set the value of this property to its own key.
    : K

// Get the union of all values (which are now the keys that have not been set to `never`)
}[keyof T]

// Pick just the keys from the class that are ClassDataKeys.
type ClassData<T> = Pick<T, ClassDataKeys<T>>

// Works!
const test1: ClassData<SomeClass> = {
  foo: 'asd',
  bar: 'asd',
}
Run Code Online (Sandbox Code Playgroud)

操场

这是一个两步过程。首先是使用映射类型和条件来测试每个属性是否是一个函数。然后收集那些不是函数的属性名称。最后,仅选择被视为类数据的属性名称。