I have a function like this:
private myFunc = (myNumber: number) => {
if (myNumber === 1) {
console.log('here');
}
}
Where myNumber is 1, I don't get the console output. From having a look at the console, I can see that myNumber is being treated as a different type (string). Changing the code like this works:
private myFunc = (myNumber: number) => {
if (myNumber == 1) {
console.log('here');
}
}
I was under the impression that Typescript would issue a 'compile' error in this case, but it doesn't seem to. Can anyone tell me why?
Yes, Typescript would show a compile time error if you'd do:
myFunc("1");
However, as you seem to call it at runtime, Typescript can't check for it.
Typescript use a static type checking ( typescript is not present at the runtime ) so if you pass a string to the function 'myNumber' will be a string. You need to add your own check inside the function
private myFunc = (myNumber: number) => {
if (parseInt(myNumber) === 1) {
console.log('here');
}
}
Related
flow 0.67.1 (but behavior continues to exist in 0.73.1)
Example:
type PropOptional = {
prop?: ComplexType
};
type ComplexType = {
callable: () => void,
anotherCallable: () => void
};
function usePropOptional(arg1: PropOptional) {
if (arg1.prop) {
arg1.prop.callable();
arg1.prop.anotherCallable();
arg1.prop.callable();
}
};
The function checks for the presence of arg1.prop before accessing any properties on arg1.prop. This should be sufficient to verify that arg1.prop is defined.
Flow is fine with the first time an arg1.prop property is accessed, which is the call to arg1.prop.callable() on the first line inside the if block. However, flow generates errors on subsequent attempts to access arg1.prop properties in the exact same if block:
arg1.prop.anotherCallable();
arg1.prop.callable();
I am forced to either prepend each line with a rote arg1.prop && truthy check, or reassign arg1.prop to a local variable inside the if block:
function usePropOptional(arg1: PropOptional) {
if (arg1.prop) {
const reallyExists = arg1.prop;
reallyExists.callable();
reallyExists.anotherCallable();
reallyExists.callable();
}
};
This doesn't feel right. What am I doing wrong or missing?
You can check this in a flow repl here on flow.org.
This is documented in FlowType's Type Refinement section:
Refinement Invalidations
It is also possible to invalidate refinements, for example:
// #flow
function otherMethod() { /* ... */ }
function method(value: { prop?: string }) {
if (value.prop) {
otherMethod();
// $ExpectError
value.prop.charAt(0);
}
}
The reason for this is that we don’t know that otherMethod() hasn’t
done something to our value.
...
There’s a straightforward way to get around this. Store the value
before calling another method and use the stored value instead. This
way you can prevent the refinement from invalidating.
// #flow
function otherMethod() { /* ... */ }
function method(value: { prop?: string }) {
if (value.prop) {
var prop = value.prop;
otherMethod();
prop.charAt(0);
}
}
So the workaround in your final case appears to be the suggested way to avoid this problem.
I have this simple code written in python to create a small
Cards game and I want to make the same using typescript but I'm
facing a big problem with 'this' in my main class in Typescript
this is the original python class:
class deck:
card_type=['Hearts ','Diamonds','Spades','Clubs']
card_rank=[2,3,4,5,6,7,8,9,10,'A','J','Q','K']
full_deck=[]
def build_deck(self):
single={}
for card in self.card_type:
for n in self.card_rank:
single={n: card}
self.full_deck.append(single)
shuffle(self.full_deck)
def reshuffle (self):
print('Re-shuffling again!')
shuffle(self.full_deck)
def choose_card(self):
chosen=choice(self.full_deck)
the_index= self.full_deck.index(chosen)
self.full_deck.pop(the_index)
return chosen
def pick_hand(self, number_of_cards):
hand=[]
new_card={}
for i in range(number_of_cards):
new_card = self.choose_card()
hand.append(new_card)
return hand
And in my main game file I do something like this:
from classes import deck
deck1= deck()
deck1.build_deck()
my_hand=deck1.pick_hand(3)
compu_hand=deck1.pick_hand(3)
But when I try to create a similar class in type script I wrote the following:
export class deck {
single_card: {
cType: string;
cNumber: any;
};
fullDeck: any[] = [];
card_type=['Hearts ','Diamonds','Spades','Clubs'];
card_rank=[2,3,4,5,6,7,8,9,10,'A','J','Q','K'];
shuffle() {
let counter = this.fullDeck.length;
// While there are elements in the array
while (counter > 0) {
// Pick a random index
let index = Math.floor(Math.random() * counter);
// Decrease counter by 1
counter--;
// And swap the last element with it
let temp = this.fullDeck[counter];
this.fullDeck[counter] = this.fullDeck[index];
this.fullDeck[index] = temp;
}
// return this.fullDeck;
}
buildDeck (){
for (let t in this.card_type) {
for ( let n in this.card_rank) {
this.single_card.cType = this.card_type[t];
this.single_card.cNumber = this.card_rank[n];
this.fullDeck.push(this.single_card);
console.log(this.single_card);
}
}
// this.shuffle()
}
}
When I try to use the class from the main 'ts' file like so:
import {deck} from './myclasses'
$(document).ready (function(){
let deck1= new deck;
deck1.buildDeck();
});
The console.log call returns the same error :
jQuery.Deferred exception: Cannot set property 'cType' of undefined
TypeError: Cannot set property 'cType' of undefined
at deck.buildDeck (file:///run/media/Work/HTML_Porjects/Game_TS/built/myclasses.js:132:44)
How is it undefined?
What do I need to do to make the Typescript code work like the Python code?
Thanks in advance ...
The error simply states that single_card is undefined, which it is:
class deck {
single_card: {
cType: string;
cNumber: any;
};
// …
}
This will declare the property single_card on the TypeScript class, so that the compiler will accept when you refer to the single_card property of an object of that type (e.g. when doing this.single_card). However, doing so will not actually assign an object of that type to the object. So for the compiled JavaScript (where type information is removed), that property does not exist since you never assign to it. You can easily verify that by looking at the compiled JavaScript there.
So what you would need to do first is assign something to single_card just like you did in the Python version:
this.single_card = {}
However, if you actually look at your Python version, single_card is not a member of the object and it actually doesn’t make any sense for it to be. You are using that to construct the card object you are then adding to the fullDeck array. In Python, it is a local variable, so you should make it a local variable in the TypeScript version too:
buildDeck() {
for (const t of this.card_type) {
for (const n of this.card_rank) {
const single_card = {
cType: this.card_type[t],
cNumber: this.card_rank[n]
};
this.fullDeck.push(single_card);
}
}
}
Btw. you also want to use a for…of loop there instead of for…in.
You should also think about making fullDeck properly typed. Right now it is an array of any, so it can store any object. But what you want to do is actually just keep objects in there that look the way single_card looks. So consider declaring a type for this:
interface SingleCard {
cType: string;
cNumber: any;
}
Then, you can properly type fullDeck:
fullDeck: SingleCard[] = [];
I am using angular2 with typescript and i have defined a class
export class Example{
//.../
const self: all = this;
functionToCall(){
//.. Do somerthing
}
mainFunctionCall(){
somepromise.then(x => self.functionToCall('url/'+ x.name ) )
}
}
But it keeps throwing error about functionToCall being undefined.
Im quite new to typescript/angular#
is there any rule that prevents this to be correct? Or what is the correct way to invoke method of class inside another method ?
No need for such a hack here, since lambda functions capture the this reference of the outer scope. You can just simply write:
const somepromise = Promise.resolve({name:"noone"});
class Example {
functionToCall(x : string) {
console.log(x);
}
mainFunctionCall() {
somepromise.then(x => this.functionToCall('url/'+ x.name ) )
}
}
(new Example()).mainFunctionCall();
Edit Code snippet updated to include all details. Can be run in the typescript playground.
I declared an interface like this:
interface IConfigAdmin {
contentCreatedBy: number;
}
Here I am using it:
private getDefaultAdminConfigs = (): IConfigAdmin => {
return {
contentCreatedBy: null
};
}
If I try to set this to [] instead of null it gives an error as I would expect but
why is it that when I hover over contentCreatedBy in VS2013 that it says this is
a (property) contentCreatedBy: any
You can fix this by casting it to IConfigAdmin first. This way you get autocompletion to while typing.
I guess it could have inferred the type because of the return statement but I'm not sure.
return <IConfigAdmin> { }
See playground: link
I have a function that I want to pass an argument to, however I want it to default to 0.
Is it possible todo it similarly to PHP, like:
function byMonth(export=0) {
Many thanks
Dont do this
function byMonth(export){
export = export || 0;
alert(export);
}
Edit:
The previous version has a silent bug, I'm leaving it just as an example of what NOT TO DO.
The problem is, suppose you pass the function the argument false, it will take the default value although you actually called it with an argument.
All this other parameters will be ignored and the default will be used (because of javascript concept of falsy)
The number zero 0
An empty string ""
NaN
false
null
and (obviously) undefined
A safer way to check for the presence of the parameter is:
function byMonth(export){
if(export === undefined) export = 0;
}
Edit 2:
The previous function is not 100% secure since someone (an idiot probably) could define undefined making the function to behave unexpectedly. This is a final, works-anywhere, bulletproof version:
function byMonth(export){
var undefined;
if(export === undefined) export = 0;
}
You can set a default inside, like this:
function byMonth(export) {
export = export || 0;
//your code
}
I'm more than 6 years late, but now with ES6, there is another solution. Pablo Fernandez said that you can set undefined to a value and you should check like this:
function byMonth(export){
var undefined;
if(export === undefined) export = 0;
}
Well, now you can do this:
function byMonth(export){
if(export === void 0) export = 0;
}
void 0 always evaluates to the "real" undefined.