英文:
typescript: call signatures example question
问题
以下是翻译好的内容:
我正在学习 TypeScript 中的调用签名,需要 TypeScript 专家的帮助:
以下代码可以编译,但在 'typescript playground' 中运行时会导致运行时错误。
运行时错误为:([ERR]:logFunc 不是一个函数)
type LogFunctionWithPrefixCB = {
logPrefix: string;
(stringToLog: string): void; // 这是快捷方式 - 据说 LogFunctionWithPrefixCB 类型是可调用的(可以将其作为函数调用)
}
function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB {
let loggerFunc = function (this: LogFunctionWithPrefixCB, stringToLog: string) {
console.log(`${this.logPrefix}: ${stringToLog}`);
};
let ret = {
logPrefix: prefixStr,
call: loggerFunc
};
return ret as LogFunctionWithPrefixCB;
}
// 使用
function doSomething(logFunc: LogFunctionWithPrefixCB) {
logFunc("hello world"); // 没有编译错误 - 但会得到运行时错误 "logFunc 不是一个函数"
}
let logger = makeLogFunctionWithPrefixCB("prefix:");
doSomething(logger);
现在下一个示例不能编译,但运行后会得到预期结果:(参见 logfunc.call(...))
TypeScript 编译错误为:"Expected 2 arguments, but got 1."
type LogFunctionWithPrefixCB = {
logPrefix: string;
(stringToLog: string): void; // 这是快捷方式 - 据说 LogFunctionWithPrefixCB 类型是可调用的(可以将其作为函数调用)
}
function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB {
let loggerFunc = function (this: LogFunctionWithPrefixCB, stringToLog: string) {
console.log(`${this.logPrefix}: ${stringToLog}`);
};
let ret = {
logPrefix: prefixStr,
call: loggerFunc
};
return ret as LogFunctionWithPrefixCB;
}
// 使用
function doSomething(logFunc: LogFunctionWithPrefixCB) {
logFunc.call("hello world"); // 可以工作,但 TypeScript 编译错误 "Expected 2 arguments, but got 1."
}
let logger = makeLogFunctionWithPrefixCB("prefix:");
doSomething(logger);
英文:
I am learning about typescript call signatures and need the help of a typescript expert:
The following code compiles, but running it in 'typescript playground' results in a runtime error.
The runtime error is: ([ERR]: logFunc is not a function)
type LogFunctionWithPrefixCB = {
logPrefix: string;
(stringToLog: string) : void; // that's the shortcut - supposedly type LogFunctionWithPrefixCB is callable (can call it as a function)
}
function makeLogFunctionWithPrefixCB( prefixStr : string) : LogFunctionWithPrefixCB {
let loggerFunc = function(this : LogFunctionWithPrefixCB, stringToLog: string) {
console.log(`${this.logPrefix}: ${stringToLog}`);
};
let ret = {
logPrefix: prefixStr,
call : loggerFunc
};
return ret as LogFunctionWithPrefixCB;
}
// using the
function doSomething(logFunc : LogFunctionWithPrefixCB) {
logFunc("hello world"); // no compilation error - but get runtime error "logFunc is not a function "
}
let logger = makeLogFunctionWithPrefixCB("prefix:");
doSomething(logger);
Now the next example does not compile, but it runs and gives the expected result: (see logfunc.call(...))
The typescript compilation error is: "Expected 2 arguments, but got 1."
Tried lots of typescript versions - all with the same result.
type LogFunctionWithPrefixCB = {
logPrefix: string;
(stringToLog: string) : void; // that's the shortcut - supposedly type LogFunctionWithPrefixCB is callable (can call it as a function)
}
function makeLogFunctionWithPrefixCB( prefixStr : string) : LogFunctionWithPrefixCB {
let loggerFunc = function(this : LogFunctionWithPrefixCB, stringToLog: string) {
console.log(`${this.logPrefix}: ${stringToLog}`);
};
let ret = {
logPrefix: prefixStr,
call : loggerFunc
};
return ret as LogFunctionWithPrefixCB;
}
// using the
function doSomething(logFunc : LogFunctionWithPrefixCB) {
logFunc.call("hello world"); // works, but typescript compilation error "Expected 2 arguments, but got 1 "
}
let logger = makeLogFunctionWithPrefixCB("prefix:");
doSomething(logger);
答案1
得分: 1
以下是翻译好的内容:
有多种方法可以创建具有属性的函数。最简单的方法是将函数值创建为const
,然后随后添加属性,这在TypeScript中是明确支持的。示例代码如下:
const f = function(){ /*⋯*/ };
f.prop = 123;
这是您可以采取的基本方法。但是:
您的函数的形式如下:
const f = function(stringToLog) {
console.log(`${this.logPrefix}: ${stringToLog}`);
}
f.logPrefix = prefixStr;
但唯一能够起作用的方式是如果函数被调用的this
上下文恰好是函数本身。这非常不太可能。如果只是像这样调用它 f("")
,那么根本没有this
上下文(它几乎肯定会是undefined
)。在调用之前,您必须将其bind
到自身,像这样 f.bind(f)("")
。如果您希望这个过程自动发生,那么您需要定义类似于 const g = f.bind(f)
。但是现在,g
只是一个没有额外logPrefix
属性的函数。这很混乱,比必要复杂得多。操纵this
可能不是您想要的。
相反,您可以在使用this
的地方直接引用函数对象本身。这将我们带到以下实现:
function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB {
const loggerFunc = function (stringToLog: string) {
console.log(`${loggerFunc.logPrefix}: ${stringToLog}`);
};
loggerFunc.logPrefix = prefixStr;
return loggerFunc;
}
这段代码可以编译而不会出错,我们可以看到它的工作方式:
function doSomething(logFunc: LogFunctionWithPrefixCB) {
logFunc("hello world");
}
let logger = makeLogFunctionWithPrefixCB("prefix");
doSomething(logger); // "prefix: hello world"
logger.logPrefix = "changedPrefix";
doSomething(logger); // "changedPrefix: hello world"
看起来不错。logger
对象的类型为LogFunctionWithPrefixCB
,因此它具有logPrefix
属性,如果我们更改该属性,它将按预期方式更改logger
函数的行为。
英文:
There are multiple ways to make a function that also has properties on it. The easiest way to do so is to create your function value as a const
and then just add the properties afterward, which is explicitly supported in TypeScript. Something like:
const f = function(){ /*⋯*/ };
f.prop = 123;
That is the basic approach you can take. But:
Your function is of the form
const f = function(stringToLog) {
console.log(`${this.logPrefix}: ${stringToLog}`);
}
f.logPrefix = prefixStr;
but the only way that would work is if the this
context on which the function is called happens to be the function itself. And this is very, very unlikely. If you just call it like f("")
, then there's no this
context at all (it would almost certainly be undefined
). You'd have to bind
it to itself before calling it, like f.bind(f)("")
. And if you wanted this to happen automatically, then you'd need to define something like const g = f.bind(f)
. But now g
is just a function without the extra logPrefix
property. It's a mess, and much more complicated than necessary. Messing with this
is probably not what you want.
Instead you can just refer to the function object directly where you were using this
. That brings us to this implementation:
function makeLogFunctionWithPrefixCB(prefixStr: string): LogFunctionWithPrefixCB {
const loggerFunc = function (stringToLog: string) {
console.log(`${loggerFunc.logPrefix}: ${stringToLog}`);
};
loggerFunc.logPrefix = prefixStr;
return loggerFunc;
}
That compiles without error, and we can see how it works:
function doSomething(logFunc: LogFunctionWithPrefixCB) {
logFunc("hello world");
}
let logger = makeLogFunctionWithPrefixCB("prefix");
doSomething(logger); // "prefix: hello world"
logger.logPrefix = "changedPrefix";
doSomething(logger); // "changedPrefix: hello world"
Looks good. The logger
object is of type LogFunctionWithPrefixCB
and so it has a logPrefix
property, and if we alter that property it alters the behavior of logger
's function in the expected way.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论