首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TypeScript:类中动态声明的方法

TypeScript:类中动态声明的方法
EN

Stack Overflow用户
提问于 2020-03-31 13:30:26
回答 3查看 1.3K关注 0票数 1

我有一些代码,比如:

代码语言:javascript
运行
复制
const methodsList = [
  'foo',
  'bar',
  // ... 20 other items ...
]

export class Relayer {
  constructor() {
    for (const methodName of methodsList) {
      this[methodName] = (...args) => {
        // console.log('relaying call to', methodName, args)
        // this is same for all methods
      }
    }
  }
}

const relayer = new Relayer()

relayer.foo('asd') // TS error
relayer.bar('jkl', 123) // TS error

现在,当我使用类实例时,TypeScript在调用relayer.foo()relayer.bar()时会发出抱怨。要使代码编译,我必须将其转换为as any或类似的代码。

我有一个声明foobar和其他方法的接口:

代码语言:javascript
运行
复制
interface MyInterface {
  foo: (a: string) => Promise<string>
  bar: (b: string, c: number) => Promise<string>
  // ... 20 other methods
}

如何让TypeScript学习动态声明的foobar类方法?declare语法在这里有用吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-04-09 23:23:27

第一步是创建一个类型或接口,当用methodsList中的值进行索引时,结果将是一个函数:

代码语言:javascript
运行
复制
// The cast to const changes the type from `string[]` to
// `['foo', 'bar']` (An array of literal string types)
const methodsList = [
    'foo',
    'bar'
] as const

type HasMethods = { [k in typeof methodsList[number]]: (...args: any[]) => any }

// Or
type MethodNames = typeof methodsList[number]  // "foo" | "bar"
                   // k is either "foo" or "bar", and obj[k] is any function
type HasMethods = { [k in MethodNames]: (...args: any[]) => any }

然后,在构造函数中,为了能够分配methodsList的键,您可以添加一个类型断言,即this is HasMethods

代码语言:javascript
运行
复制
// General purpose assert function
// If before this, value had type `U`,
// afterwards the type will be `U & T`
declare function assertIs<T>(value: unknown): asserts value is T

class Relayer {
    constructor() {
        assertIs<HasMethods>(this)
        for (const methodName of methodsList) {
            // `methodName` has type `"foo" | "bar"`, since
            // it's the value of an array with literal type,
            // so can index `this` in a type-safe way
            this[methodName] = (...args) => {
                // ...
            }
        }
    }
}

现在,在构造之后,您必须仍然转换类型:

代码语言:javascript
运行
复制
const relayer = new Relayer() as Relayer & HasMethods

relayer.foo('asd')
relayer.bar('jkl', 123)

在使用工厂函数进行构造时,还可以消除这些强制转换:

代码语言:javascript
运行
复制
export class Relayer {
    constructor() {
        // As above
    }

    static construct(): Relayer & HasMethods {
        return new Relayer() as Relayer & HasMethods
    }
}

const relayer = Relayer.construct()

另一种方法是创建一个新的类和类型断言,new将生成一个HasMethods对象:

代码语言:javascript
运行
复制
class _Relayer {
    constructor() {
        assertIs<HasMethods>(this)
        for (const methodName of methodsList) {
            this[methodName] = (...args) => {
                // ...
            }
        }
    }
}

export const Relayer = _Relayer as _Relayer & { new (): _Relayer & HasMethods }

const relayer = new Relayer();

relayer.foo('asd')
relayer.bar('jkl', 123)

或者,如果您只使用new,然后在methodsList中使用方法,则可以:

代码语言:javascript
运行
复制
export const Relayer = class Relayer {
    constructor() {
        assertIs<HasMethods>(this)
        for (const methodName of methodsList) {
            this[methodName] = (...args) => {
                // ...
            }
        }
    }
} as { new (): HasMethods };

您还可以使用MyInterface接口而不是HasMethods,跳过第一步。这也为你的通话提供了类型安全。

票数 4
EN

Stack Overflow用户

发布于 2020-03-31 13:55:16

使用以下语法:

代码语言:javascript
运行
复制
export class Relayer { 
  constructor() {}
  public foo(){
    // your foo method
    this.executedOnEachFunction();
  }
  public bar(){
    // your bar method
    this.executedOnEachFunction();
  }
  executedOnEachFunction(){
    // what you want to do everytime
  }
}

https://repl.it/repls/LawfulSurprisedMineral

票数 1
EN

Stack Overflow用户

发布于 2020-03-31 14:06:05

对我来说,这听起来像是需要一个接口。

代码语言:javascript
运行
复制
interface MyInterface {
 foo(): void; // or whatever signature/return type you need
 bar(): void;
  // ... 20 other items ...
}

export class Relayer implements MyInterface {
  constructor() {}

  foo(): void {
    // whatever you want foo to do
  }

  // ... the rest of your interface implementation
}

它看起来像是在实现某种类型的接口。在构造函数中,您定义的是什么方法实现,而不是在类主体中定义它们。可能有助于阅读类类型接口

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60951788

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档