打字稿通用“一次”功能

时间:2019-09-24 15:24:33

标签: typescript

我正在使用FP中的一次函数Once()。当我使用TS时,我需要输入它,但是无法实现此实现。到目前为止,这是我的努力;

const once = <T, U>(fn: (arg: T) => U): () => U | undefined => {
let done = false;
return function(this: (args: T) => U) {
    return done ? void 0 : ((done = true), fn.apply(this, arguments));
};

}

我正在将此用于类中的方法:

class CSVOutput extends LogOutput {
private print_headers: (logStat: IStats) => void;
constructor() {
    super();
    this.print_headers = once((logStat: IStats) => {
        console.log(Object.keys(logStat).join(','));
    });
}
public print(logStat: IStats) {
    this.print_headers(logStat);
    console.log(Object.values(logStat).join(','));
}

}

我的tsconfig.json看起来像

{
"compilerOptions": {
    "esModuleInterop": true,
    "lib": ["es6", "es7", "es2017"],
    "module": "commonjs",
    "sourceMap": true,
    "target": "es6",
    "types": ["node", "mocha"],
    "allowJs": true,
    "outDir": "./dist",
    "preserveSymlinks": true,
    "strict": true,
    "baseUrl": "."
}

}

我收到TS警告Argument of type 'IArguments' is not assignable to parameter of type '[T]'.

如何在打字稿中正确编写此功能?

1 个答案:

答案 0 :(得分:1)

我想我会把它改成这样:

const once = <A extends any[], R, T>(
  fn: (this: T, ...arg: A) => R
): ((this: T, ...arg: A) => R | undefined) => {
  let done = false;
  return function (this: T, ...args: A) {
    return done ? void 0 : ((done = true), fn.apply(this, args));
  };
};

在这里,我们接受任何函数类型,甚至包括希望设置this上下文的方法。请注意,我一直使用rest tuple types来表示参数列表。 arguments的类型在TypeScript中不是很强,可能是因为对于ES2015 +代码,无论如何您都应该使用rest参数。无论如何,返回类型once()是一个函数,该函数具有与this相同的fn上下文和参数列表,并且具有相同的返回类型或undefined。我认为这种打字方式最适合您:

function yell(x: string) {
  return x.toUpperCase() + "!!!!!!!!!";
}

const yellOnce = once(yell);
// const yellOnce: (this: unknown, x: string) => string | undefined

console.log(yellOnce("hello")); // HELLO!!!!!!!!!;
console.log(yellOnce("goodbye")); undefined

好的,希望能有所帮助;祝你好运!

Link to code