I have a standalone function that's meant to use the context provided by Function.prototype.call
.
For example:
function foo () {
return this.bar;
}
> foo.call({bar: "baz"})
baz
Is there a way to provide a Typescript type annotation for the this
keyword in this scenario?
The "this" keyword always points to the object that is calling a particular method. The type of "this" in an expression depends on the location in which the reference occurs: In a constructor, member function, or member accessor, this is of the class instance type of the containing class.
TypeScript - Type Annotations We can specify the type using :Type after the name of the variable, parameter or property. There can be a space after the colon. TypeScript includes all the primitive types of JavaScript- number, string and boolean. In the above example, each variable is declared with their data type.
Type keyword in typescript: In typescript the type keyword defines an alias to a type. We can also use the type keyword to define user defined types.
However, there is another way to do type assertion, using the 'as' syntax. let code: any = 123; let employeeCode = code as number; Both the syntaxes are equivalent and we can use any of these type assertions syntaxes.
First of all, you can use the special this
parameter syntax to identify the type of object you expect this
to be:
function foo (this: {bar: string}) {
return this.bar; // no more error
}
which helps if you call it directly:
foo(); // error, this is undefined, not {bar: string}
var barHaver = { bar: "hello", doFoo: foo };
barHaver.doFoo(); // acceptable, since barHaver.bar is a string
var carHaver = { car: "hello", doFoo: foo };
carHaver.doFoo(); // unacceptable, carHaver.bar is undefined
UPDATE for TS3.2+
TypeScript 3.2 introduced the --strictBindCallApply
compiler option which strongly types the .call() method of functions. If you use this (or the --strict
suite of compiler features which includes this), then the this
parameter will also enforce that foo.call()
behave as desired:
foo.call({ bar: "baz" }); // okay
foo.call({ baz: "quux" }); // error!
Playground link to code
pre TS3.2 answer follows:
But you want to use foo.call()
. Unfortunately the Function.prototype.call()
typing in TypeScript won't really enforce this restriction for you:
foo.call({ bar: "baz" }); // okay, but
foo.call({ baz: "quux" }); // no error, too bad!
Merging something better into TypeScript's Function
declaration caused me problems, (First point of ugliness; you will need to cast foo
to something) so you can try something like this:
interface ThisFunction<T extends {} = {}, R extends any = any, A extends any = any> {
(this: T, ...args: A[]): R;
call(thisArg: T, ...args: A[]): R;
}
A ThisFunction<T,R,A>
is a function with a this
of type T
, a return value of type R
, and a rest argument of type A[]
. (Second point of ugliness: you can't easily specify multiple arguments of different types in a way that will be enforced by the type system.)
You can then cast foo
to ThisFunction<{ bar: string }, string>
, (Third point of ugliness: the type system just will not infer this
types) and then finally use call()
:
(<ThisFunction<{ bar: string }, string>>foo).call({ bar: "baz" }); // okay, and
(<ThisFunction<{ bar: string }, string>>foo).call({ baz: "quux" }); // error, hooray!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With