I've just started with TypeScript and I'm trying to understand why the following inline object definition isn't considered valid. I have a collection of objects - their type is irrelevant (to me), but they implement the interface so that when I iterate through them I know that the interface methods will be present in each object in the collection.
I came across a "compiler" error when I tried to create an object with private information required to implement the required method:
interface Doable {
do();
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
doThatThing({
private message: 'ahoy-hoy!', // compiler error here
do: () => {
alert(this.message);
}
});
The compiler error message is "Argument of type '{ message: string, do: () => void; }' is not assignable to type Doable. Object literal must specify known properties, and 'message' does not exist in type Doable". Note that the same message is given if I define the object outside of the function call, i.e.
var thing: Doable;
thing = {
private message: 'ahoy-hoy!', // error here
do: () => {
alert(this.message);
}
};
doThatThing(thing);
The same error occurs if I add "unexpected" methods as well:
doThatThing({
do: () => {
alert("ahoy hoy");
},
doSecretly: () => { // compiler error here now
alert("hi there");
}
});
I looked at the JavaScript and discovered that this within the inline object definition was being scoped to the global object:
var _this = this; // wait, no, why!?
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // uses global
}
});
I tried searching for information on inline implementations of interfaces in TypeScript, but couldn't find anything speaking to this issue specifically.
I can confirm that the "fixed" compiled JS works as intended:
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(this.message);
}
});
...and that makes sense to me, because (as far as I understand) this is implicitly calling the Object constructor, so this should be scoped to the new Object instance.
It seems like the only solution is to declare each implementation as a class implementing the interface, but that feels really regressive/heavy-handed since I'm only going to have one instance of each class. If the only contract with the called function is implementing the interface, then why can't the object contain additional members?
Sorry, this turned out longer than I intended ...in summary, I'm asking:
Why is that inline interface implementation ("anonymous class", as would be said in Java) considered invalid in TypeScript? Specifically, what does that compiler error mean, and what does it protect against?
Why is the scope-reassignment to the global object generated in the "compiled" JavaScript?
Assuming it's my error (e.g. that the compiler error is necessary for protecting against some undesirable condition), is the only solution really to explicitly declare a class in advance, like so?
interface Doable {
do() : void;
}
class DoableThingA implements Doable { // would prefer to avoid this ...
private message: string = 'ahoy-hoy';
do() {
alert(this.message);
}
}
class DoableThingB implements Doable { // ... as well as this, since there will be only one instance of each
do() {
document.getElementById("example").innerHTML = 'whatever';
}
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
var things: Array<Doable>;
things = new Array<Doable>();
things.push(new DoableThingA());
things.push(new DoableThingB());
for (var i = 0; i < things.length; i++) {
doThatThing(things[i]);
}
P.S. The compiler error only appeared when I upgraded to TS 1.6 today, although the faulty scope bug in the compiled JS occurs in both 1.6 and 1.5.
Update: François Cardinaux provided a link to this answer, which recommends using a type assertion, but this only removes the compiler error and actually causes a logic error due to improper scope:
interface Doable {
do();
}
function doThatThing (doableThing: Doable) {
doableThing.do();
}
doThatThing(<Doable>{ // assert that this object is a Doable
private message: 'ahoy-hoy!', // no more compiler error here
do: () => {
alert(this.message);
}
});
Looking at the compiled JS, this is incorrect:
var _this = this; // very wrong, and now hidden
function doThatThing(doableThing) {
doableThing.do();
}
doThatThing({
message: 'ahoy-hoy!',
do: function () {
alert(_this.message); // s/b "this.message", which works in JS (try it)
}
});
OK, I finally discovered the problem to question 2 - I was using the fat arrow => to declare the object's method here:
doThatThing(<Doable>{
private message: 'ahoy-hoy!',
do: () => { // using fat arrow: global scope replaces new object's scope
alert(this.message);
}
});
...which "sucked" the global scope into the method. The problem is fixed using the longer syntax, like so:
doThatThing(<Doable>{
private message: 'ahoy-hoy!',
do: function() { // using "regular" anonymous function syntax, "this" meaning is preserved
alert(this.message);
}
});
So in summary:
unanswered;
There was a typo in my code, and I should have been using "function()" instead of "=>"; and,
Type-asserting the object with the interface removes the compiler error.
Related
I think this has been addressed somewhere, at some point, just for the life of me I can't remember so here's my question:
I'm doing some javascript work that will be loaded into an existing application. This application has crap loads of functions available and hardly any of it is known to me except some that I want to actually use. So lets say that I know for a fact that window.srslyUsefulFunction will be available to me and I don't care much for porting this in to a typescript definition.
So the question is how do I use window.srslyUsefulFunction in my own typescript file without creating a definition for it?
Example:
class MyClass {
public MyMethod (id : string) : void {
// do something
var result = window.srslyUsefulFunction(id);
// do something (with the result)
}
}
You can add the function to the Window interface and then use it in your TypeScript program:
interface Window {
srslyUsefulFunction(id: number): void;
}
class MyClass {
doSomething() {
window.srslyUsefulFunction(1);
}
}
I have simple workaround.
In index.html
function playIntro() {
intro = new lib.intro();
onlinePlayer.contentContainer.addChild(intro);
stage.update();
}
in my Main.ts I call it like that:
private onClick(event): void {
if (window.hasOwnProperty('playIntro')) {
window['playIntro'].call();
}
}
So... if you want to call "blind" js function from global scope, just use window["foo"].call();
Check if the function exists. If it doesn't, declare it:
if(!window.hasOwnProperty('srslyUsefulFunction')
|| typeof window['srslyUsefulFunction'] !== "function"){
window['srslyUsefulFunction'] = function(){
console.log("You're only running a dummy implementation of srslyUsefulFunction here!");
};
}
I found this type in the ES5 definitions for TypeScript, and was wondering what it does because the simple description is kind of vague.
/**
* Removes the 'this' parameter from a function type.
*/
type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;
source code
The description implies that this is a type, but when you look at the code it's not clear exactly what they mean by it.
I have searched the Microsoft documentation for TypeScript, but there appears to be no references to how this is used or why.
Here is an example of source code where I've seen it used.
export class Example {
funcRef: OmitThisParameter<()=> void>;
func() { }
constructor() { this.funcRef = this.func.bind(this); }
}
There doesn't appear to me that there is any static type advantages here. The usage of funcRef seems to have no restrictions. Could it be that this prevents funcRef from being used as a constructor function?
If I make the following changes the source code compiles without any issues.
export class Example {
funcRef: () => void;
func() { }
constructor() { this.funcRef = this.func.bind(this); }
}
Isn't this type identical to an arrow function, but we don't declare types for arrow functions.
So I'm looking for an answer that explains what type advantages this has, and why we should use this type, because I very rarely see it used.
Can you give a source code example that would cause TypeScript to raise a type warning?
A this parameter is a pseudo-parameter that you put first in a function signature, and it says that inside the function, the this context will have the defined type. It makes the function more specific, in that both the implementation of the function and any callers of the function will treat it as if the function is a method of a particular type.
For example:
function addX(this: { x: number }, y: number): number {
return this.x + y;
}
The function addX() must be bound to an object with a numeric x property to be called successfully. The implementation doesn't complain about this.x because of this. That prevents you from calling it in a standalone way:
addX(10); // error! you can't call this function by itself
Instead, you have to bind it correctly... here's one way:
const val = {
x: 123,
addX: addX
};
val.addX(10); // okay, you're calling it as a method of type {x: number}
And if you bind it to the wrong type of thing you get an error also:
const badVal = {
x: "whoopsie",
addX: addX
};
badVal.addX(10); // error! string is not a number, can't do this
So a function with a declared this parameter is less forgiving about where it's used. If you have a function with a this parameter and would like to call it in an unapproved way, you can use the OmitThisParameter<> utility type:
const unsafeAddX: OmitThisParameter<typeof addX> = addX; // okay
unsafeAddX(10); // no error (but kablooey at runtime, "this is undefined")
I wouldn't necessarily recommend doing this, but just like there are times when type assertions are useful, there are probably times when ignoring a this context restriction is useful.
So, backing up to this:
funcRef: OmitThisParameter<() => void>; // 🤔
That evaluates to precisely () => void. The type () => void has no this parameter, so omitting it does nothing. There's really no reason in the world to use the type OmitThisParameter<() => void>, and I suspect it's a mistake.
Looking at that class and squinting I can imagine doing something like this:
export class Example {
funcRef: OmitThisParameter<Example["func"]>;
func(this: Example) {}
constructor() {
this.funcRef = this.func.bind(this);
}
}
I've added the this restriction to the func() method (you'd think this contexts on actual class methods would automatically happen, but they don't. Slows down the compiler too much, I guess.), and then made the type of funcRef such that it is the same type as func with the restriction lifted. And that causes the following behavior:
const x = new Example();
const func = x.func;
func(); // error! bad this context
const funcRef = x.funcRef;
funcRef(); // okay
Oh well, hope that helps. Good luck!
Link to code
i've got a basic question about instancing of an object in NodeJS and different ways to declare classes.
I've saw few tutorials but no tutorial has descriped, when i should use which way or why there are different ways.
I want to create a instance of an object and have created two code-snippets which does exactly the same but with a completly different code.
My question: Do i get the same result or is there something special i cannot see that it is different and moreover, which way should i use?
ExampleA:
class ExampleA {
constructor () { }
method() {
console.log("Hello world");
}
}
module.exports.ExampleA = ExampleA;
ExampleB:
function ExampleB() {
}
NoSQL1.prototype.method = function() {
console.log("Hello world");
}
module.exports.ExampleB = ExampleB;
If i got it right, in ExampleB i just add a new function to a existing class within the "Classname.prototype.Method"
Maybe there are even more ways to go? As a C# developer i prefer the ExampleA, currently...
There's not a major difference. Javascript doesn't have traditional Classes. Everything is just an Object and the syntax of example A is basically just around because of convention and Javascript trying to cater to both OOP and functional programming.
But only the first pattern allows you to make private variables, through the use of a closure.
You get the same result.
Class is a syntactic sugar in latest version of ECMAScript(ES).
JavaScript is still prototype based, so you should be carefull about refrence on sepcial word this because for example:
class ExampleA {
constructor() {
this.text = 'Hello World!'
}
method() {
console.log(this.text);
}
}
let a = new EampleA()
a.method() // will print 'Hello World'
let m = a.method;
m() // will throw exception "Cannot read property 'text' of undefined
let b = {text: 'Hi'};
m.call(b) // will print 'Hi'
I use typescript with breeze. How can i pass a typescript function to executeQuery.then?
class MyClass{
...
myFunc(data:any):void{
...
}
doQuery():void{
var manager = new breeze.EntityManager('/breeze/dbentities');
var query = breeze.EntityQuery.from("Corporations").where("Name", "startsWith", "Zen");
manager.executeQuery(query)
.then(this.myFunc); // does not work!
}
}
Use this.myFunc instead of myFunc.
It might be a context problem. Try this.myFunc.bind(this) instead of this.myFunc.
For more information about context, refer "this" and "Function.prototype.bind" article from MDN.
First, this is working perfectly in my own classes. What is "not working", what error message is thrown?
Second, to be sure that "this" is my typescript class context I always use a lambda like this:
doQuery(): void {
...
manager.executeQuery(query).then((data: breeze.QueryResult) => {
this.myFunc(data);
});
}
In this case the TS compiler produces a "var _this = this" at the beginning of the doQuery function which is your class context and converts the "this.myFunc(data)" call to "_this.myFunc(data)".
And better use type declarations like "breeze.QueryResult" instead of any.
I think this has been addressed somewhere, at some point, just for the life of me I can't remember so here's my question:
I'm doing some javascript work that will be loaded into an existing application. This application has crap loads of functions available and hardly any of it is known to me except some that I want to actually use. So lets say that I know for a fact that window.srslyUsefulFunction will be available to me and I don't care much for porting this in to a typescript definition.
So the question is how do I use window.srslyUsefulFunction in my own typescript file without creating a definition for it?
Example:
class MyClass {
public MyMethod (id : string) : void {
// do something
var result = window.srslyUsefulFunction(id);
// do something (with the result)
}
}
You can add the function to the Window interface and then use it in your TypeScript program:
interface Window {
srslyUsefulFunction(id: number): void;
}
class MyClass {
doSomething() {
window.srslyUsefulFunction(1);
}
}
I have simple workaround.
In index.html
function playIntro() {
intro = new lib.intro();
onlinePlayer.contentContainer.addChild(intro);
stage.update();
}
in my Main.ts I call it like that:
private onClick(event): void {
if (window.hasOwnProperty('playIntro')) {
window['playIntro'].call();
}
}
So... if you want to call "blind" js function from global scope, just use window["foo"].call();
Check if the function exists. If it doesn't, declare it:
if(!window.hasOwnProperty('srslyUsefulFunction')
|| typeof window['srslyUsefulFunction'] !== "function"){
window['srslyUsefulFunction'] = function(){
console.log("You're only running a dummy implementation of srslyUsefulFunction here!");
};
}