打字稿自定义属性名称

时间:2018-06-12 16:22:25

标签: typescript

我目前面临以下情况:

我编写JS模块的typescript定义,这个模块的调用函数如下所示:

declare function module<I>(
  instance: I,
  options: module.Options
): module.Module<I>

模块命名空间:

declare namespace module {
  interface Module<I> {
    use(): any;
    after(): any;
    ready(): any;
  }

  interface Options {
    expose?: {
      use?: string;
      after?: string;
      ready?: string;
    }
  }
}

expose选项用于更改module.module中的方法名称,我不知道:

1)就像在使用,准备名和

之后具有默认回退一样

2)让用户为这些方法指定一个新名称

我不知道Typescript是否具有这种灵活性^^

1 个答案:

答案 0 :(得分:1)

是的,它有一定的灵活性,但不是很多 - 您可以使用从数据推断出方法名称的类型,但数据必须以字符串文字的形式出现 - 您不能拥有包含所需名称的变量方法,将该变量传递给module函数并神奇地获取具有该名称的类型。

而且我不确定这是否值得付出努力:

declare function module<I, U extends string = string, A extends string = string, R extends string = string>(
  instance: I,
  options: module.Options<U, A, R>
): module.Module<I, U, A, R>

declare namespace module {

  interface DefaultModule<I> {
    use(): any;
    after(): any;
    ready(): any;
    }

    type Module<I, U extends string, A extends string, R extends string> =
        string extends U ? DefaultModule<I> :
        string extends A ? DefaultModule<I> :
        string extends R ? DefaultModule<I> :
        // here we have specific names in U, A, R, not just strings
        { [u in U]: () => any } & { [a in A]: () => any } & { [r in U]: () => any }
        ;    

  interface Options<U extends string = string, A extends string = string, R extends string = string> {
    expose?: {
      use?: U;
      after?: A;
      ready?: R;
    }
  }
}

interface ExposeNames<U extends string, A extends string, R extends string> {
    useName: U;
    afterName: A;
    readyName: R;
}

function moduleOptions<U extends string, A extends string, R extends string>({useName, afterName, readyName}: ExposeNames<U, A, R>): module.Options<U, A, R> {
    return {
        expose: {use: useName, after: afterName, ready: readyName}
    }
}

const moduleA = module({}, {});
moduleA.use();

const moduleB = module({}, moduleOptions({ useName: 'use1', afterName: 'after1', readyName: 'ready1' }));
moduleB.use1();