Can I choose between Perl 6 multis that have no parameters? - raku

I can choose a multi based on some non-argument value but I have to have at least one argument so I can kludge the where in there:
our $*DEBUG = 1;
debug( 'This should print', 'Phrase 2' );
$*DEBUG = 0;
debug( 'This should not print' );
multi debug ( *#a where ? $*DEBUG ) { put #a }
multi debug ( *#a where ! $*DEBUG ) { True }
I seem to recall some trick someone used to dispatch among multis that took exactly no parameters. For example, I have a show-env routine I'd like to sprinkle around and that only does anything if I've set some debugging conditions. I could achieve it like I've shown but that's not very satisfying and it's not the clever thing I imagine I saw elsewhere:
our $*DEBUG = 1;
debug( 'This should print', 'Phrase 2' );
show-env();
$*DEBUG = 0;
debug( 'This should not print' );
show-env();
multi debug ( *#a where ? $*DEBUG ) { put #a }
multi debug ( *#a where ! $*DEBUG ) { True }
# use an unnamed capture | but insist it has 0 arguments
multi show-env ( | where { $_.elems == 0 and ? $*DEBUG } ) { dd %*ENV }
multi show-env ( | where { $_.elems == 0 and ! $*DEBUG } ) { True }
I could do something similar with optional named parameters but that's even less satisfying.
Of course, I could do just this in this simple example but this is no fun:
sub show-env () {
return True unless $*DEBUG;
dd %*ENV;
}

You could destructure the | with ().
my $*DEBUG = 1;
show-env();
$*DEBUG = 0;
show-env();
# use an unnamed capture | but insist it has 0 arguments by destructuring
multi show-env ( | () where ? $*DEBUG ) { dd %*ENV }
multi show-env ( | () where ! $*DEBUG ) { True }
show-env(42); # Cannot resolve caller show-env(42); …
Or you could have a proto declaration
proto show-env (){*}
multi show-env ( | where ? $*DEBUG ) { dd %*ENV }
multi show-env ( | where ! $*DEBUG ) { True }
show-env(42); # Calling show-env(Int) will never work with proto signature () …

A more elegant way to insist that the capture is empty is to specify it with an empty sub-signature:
multi show-env ( | () where ? $*DEBUG ) { dd %*ENV }
multi show-env ( | () where ! $*DEBUG ) { True }

Related

What is the difference between using Raku's Code.assuming method and using an anonymous Block or Sub?

The Raku docs say that Code.assuming
Returns a Callable that implements the same behavior as the original, but has the values passed to .assuming already bound to the corresponding parameters.
What is the difference between using .assuming and wrapping the Code in an anonymous Block (or Sub) that calls the inner function with some parameters already bound?
For instance, in the code below, what is the difference between &surname-public (an example the docs provide for .assuming) and &surname-block;
sub longer-names ( $first, $middle, $last, $suffix ) {
say "Name is $first $middle $last $suffix";
}
my &surname-public = &longer-names.assuming( *, *, 'Public', * );
my &surname-block = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }
surname-public( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
surname-block( 'Joe', 'Q.', 'Jr.'); # OUTPUT: «Name is Joe Q. Public Jr.»
I see that .assuming saves a bit of length and could, in some contexts, be a bit clearer. But I strongly suspect that I'm missing some other difference.
There really isn't a difference.
While the code to implement .assuming() is almost 300 lines, the important bit is only about ten lines of code.
$f = EVAL sprintf(
'{ my $res = (my proto __PRIMED_ANON (%s) { {*} });
my multi __PRIMED_ANON (|%s(%s)) {
my %%chash := %s.hash;
$self(%s%s |{ %%ahash, %%chash });
};
$res }()',
$primed_sig, $capwrap, $primed_sig, $capwrap,
(flat #clist).join(", "),
(#clist ?? ',' !! '')
);
The rest of the code in .assuming is mostly about pulling information out of the signatures.
Let's take your code and insert it into that sprintf.
(Not exactly the same, but close enough for our purposes.)
{
my $res = (
# $primed_sig v----------------------v
my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
);
# $capwrap vv
# $primed_sig v----------------------v
my multi __PRIMED_ANON (|__ ($first, $middle, $suffix)) {
# $capwrap vv
my %chash := __.hash;
# v---------------------------v #clist
$self(__[0], __[1], 'Public', __[2], |{ %ahash, %chash });
};
# return the proto
$res
}()
If we simplify it, and tailor it to your code
my &surname-public = {
my $res = (
my proto __PRIMED_ANON ($first, $middle, $suffix) { {*} }
);
my multi __PRIMED_ANON ( $first, $middle, $suffix ) {
longer-names( $first, $middle, 'Public', $suffix )
};
$res
}()
We can simplify it further by just using a pointy block.
my &surname-public = -> $first, $middle, $suffix {
longer-names( $first, $middle, 'Public', $suffix )
};
Also by just using single letter parameter names.
my &surname-public = -> $a,$b,$c { longer-names($a, $b, 'Public', $c) }
Like I said, there really isn't a difference.
In the future, it may be more beneficial to use .assuming(). After it gets rewritten to use RakuAST.

A scalar with memory, or how to correctly `tie`

This is my attempt to solve Challenge #2 of the weekly.
The challenge is very vague, so I decided to try to implement a scalar value with a memory. It's possible my understanding of how containers should work is flawed, but what I really don't understand, is, why say self.VAR.WHAT is a Proxy and not a HistoryProxy, even when I explicitly say so.
class HistoryProxy is Proxy
{
has #!history;
method HISTORY() { #!history };
method SAVE( $value ) { #!history.push($value) }
}
sub historic(::T $type, $value) {
my T $c-value = $value;
return-rw HistoryProxy.new(
FETCH => method () { $c-value },
STORE => method (T $new-value) {
say self.VAR.WHAT; # Why is this "Proxy" and not "HistoryProxy"?
self.VAR.SAVE( $c-value ); # Why does this not work?
$c-value = $new-value;
}
);
}
my $a := historic(Int, 10);
$a = 12;
$a = 14;
say $a.VAR.HISTORY; #should print [10, 12]
This does not help you get the functionality you want, but it does answer your specific questions for now:
say self.VAR.WHAT; # Why is this "Proxy" and not "HistoryProxy"?
I think this is because the Proxy class is currently not set up to be subclassed. Its new method basically does a Proxy.new instead of a self.new, so it misses the subclassing. Looking into that now.
self.VAR.SAVE( $c-value ); # Why does this not work?
self is always decontainerized. So you're always seeing the underlying value. If you want to have the actual object, you will need to change the signature of the method, e.g.:
STORE => method (\SELF: T $new-value) {
and then use:
SELF.VAR
But since the object isn't actually blessed as the subclass, this won't help you much anyway.
UPDATE: https://github.com/rakudo/rakudo/pull/3196 should allow subclassing of Proxy objects in the future.
UPDATE: with https://github.com/rakudo/rakudo/commit/d00674b31c this Pull Request got merged. It should become available in the 2019.11 Rakudo compiler release.
Thanks again Liz for adressing this so quickly. However, as i wrote on Github, while the subclassing works now, it seems to be impossible to initialize attributes of the subclass. This is fine for know, I can solve this with the get-position method.
Is this because Proxy is not a "proper" class, or am I overlooking something?
use Test;
class Scalar::History::Proxy is Proxy
{
has #!history;
has $!position = 0; # The assignment gets ignored ...
# ... so do these
submethod TWEAK( *#args )
{
say "Why oh why?";
}
submethod BUILD( *#args )
{
say "Do we never get called";
}
method get-position( \SELF: )
{
$!position // #!history.elems
}
method current-value( \SELF: )
{
#!history[ SELF.get-position ]
}
method get-history( \SELF: Bool :$all = False )
{
my $to-index = $all ?? #!history.elems - 1 !! SELF.get-position;
#!history[ ^$to-index ].Array
}
method reset-history( \SELF: )
{
#!history = ();
$!position = 0;
}
method forward-history( \SELF: $steps )
{
$!position = SELF.get-position + $steps;
$!position = #!history.elems - 1
if $!position >= #!history.elems;
$!position;
}
method rewind-history( \SELF: $steps )
{
$!position = SELF.get-position - $steps;
$!position = 0
if $!position < 0;
$!position;
}
method store-value( \SELF: $new-value, $register-duplicates )
{
# Forget stuff after rewind
if #!history.elems > SELF.get-position + 1
{
#!history.splice( SELF.get-position + 1 );
}
if !($new-value eqv SELF.current-value) || $register-duplicates
{
#!history.push( $new-value );
$!position = #!history.elems - 1;
}
}
}
class Scalar::History
{
method create( $value, ::T $type = Any, Bool :$register-duplicates = False )
{
return-rw Scalar::History::Proxy.new(
FETCH => method ( \SELF: ) {
SELF.current-value() },
STORE => method ( \SELF: T $new-value ) {
SELF.store-value( $new-value, $register-duplicates ); }
) = $value;
}
}
This passes all the tests I have
use Scalar::History;
use Test;
subtest 'untyped' =>
{
plan 2;
my $untyped := Scalar::History.create("a");
my $sub = sub foo() { * };
my $rx = rx/x/;
$untyped = $sub;
$untyped = $rx;
$untyped = 42;
ok( $untyped == 42, "Current value is correct" );
is-deeply( $untyped.VAR.get-history, ["a", $sub, $rx], "History is correct" );
}
subtest 'typed' =>
{
plan 3;
my $typed := Scalar::History.create("a", Str);
$typed = "b";
$typed = "42";
ok( $typed == "42", "Current value is correct" );
is-deeply( $typed.VAR.get-history, ["a", "b"], "History is correct" );
dies-ok( { $typed = 2; }, "Cannot assign invalid type" );
}
subtest 'duplicates' =>
{
plan 2;
my $with-duplicates := Scalar::History.create( "a", Str, :register-duplicates(True) );
$with-duplicates = "a";
$with-duplicates = "a";
is-deeply( $with-duplicates.VAR.get-history, ["a", "a"], "duplicates get registered" );
my $no-duplicates := Scalar::History.create( "a", Str );
$no-duplicates = "a";
$no-duplicates = "a";
is-deeply( $no-duplicates.VAR.get-history, [], "duplicates get ignored" );
}
subtest 'position/forward/backward' =>
{
plan 8;
my Int $int := Scalar::History.create(10, Int);
#say $int.VAR.get-position;
$int = 100 ;
$int = 1000 ;
ok( $int.VAR.get-position == 2, "current position is 2 after 3 assignments" );
$int.VAR.rewind-history(2);
ok( $int == 10, "current value is correct after rewind" );
$int.VAR.forward-history(1);
ok( $int == 100, "current value is correct after forward" );
$int.VAR.rewind-history(Inf);
ok( $int == 10, "current value equals start value after rewind to infinity" );
$int.VAR.forward-history(Inf);
ok( $int == 1000, "current value equals last known value after forward to infinity" );
$int.VAR.rewind-history(2);
is-deeply( $int.VAR.get-history, [], "history empty after rewind" );
is-deeply( $int.VAR.get-history(:all), [10, 100], "but still there if needed" );
$int = 101;
$int = 1001;
is-deeply( $int.VAR.get-history, [10, 101], "history gets truncated after rewind and assign" );
}
subtest 'behaviour' =>
{
plan 2;
sub add-one( Int $v ) { return $v + 1 }
my Int $int := Scalar::History.create(1, Int);
$int++;
$int = $int + 1;
$int = add-one( $int );
$int = 42;
is-deeply( $int.VAR.get-history, [1,2,3,4], "historic Int behaves like normal Int" ); # probably testing the language here, but meh
$int.VAR.reset-history();
is-deeply( $int.VAR.get-history(:all), [], "history can be reset" );
}
done-testing;

Is there a shorthand where One <or> More positionals match a Type in a multi signature

I have this;
multi sub infix:<+> ( Measure:D $left, Measure:D $right ) is equiv( &infix:<+> ) is export {
my ( $result, $argument ) = inf-prep( $left, $right );
return $result.add( $argument );
}
multi sub infix:<+> ( Measure:D $left, $right ) is equiv( &infix:<+> ) is export {
my ( $result, $argument ) = inf-prep( $left, $right );
return $result.add( $argument );
}
multi sub infix:<+> ( $left, Measure:D $right ) is equiv( &infix:<+> ) is export {
my ( $result, $argument ) = inf-prep( $left, $right );
return $result.add( $argument );
}
Is there a shorthand to avoid three multi sub declarations - the main aim here is to catch anything that has my custom Type i.e. Measure.
In your signature you can use a single Capture for all parameters and constraint them with a where clause inspecting the capture for the desired number of positionals and if the Type is present.
For example the following sub expects two positionals where at least one is Int:D:
sub callWithInt(|c where { .elems == 2 && .list.any ~~ Int:D }) {
# Just show the first Int:D received
"called with {c.list.first(* ~~ Int)}".say
}
If you need to define different subs with the same signature, to avoid repeating the clause, create first a subset and use it as constraint:
subset hasInt of Capture where {
.elems == 2 # Number of required positionals
&& .list.any ~~ Int:D # a Junction for the Type check
# Avoid LTA error messages
or fail('Need 2 positionals with an Int')
};
sub cwInts(hasInt |c) {
"called with {c.list.first(* ~~ Int)}".say
}
sub adder(hasInt |c) { … }
cwInts(1, 'bar'); # "called with 1"
cwInts('foo', 3); # "called with 3"
cwInts('foo', 'barr') # Error! "I need 2 positionals with an Int"
cwInts(8); # Error!

How to represent nested data structures using Perl 6 classes?

Last time I had to deal with such data, I used something like array-of-hashes, where each hash could have hash values etc. While looping through different indices/keys, it was very difficult not to get lost, so I presume there should be a better solution. Since I have no experience in OOP, I don't know, how to start...
Suppose in our city, we have a Library (whose contents has been digitized into txt-files) with several rooms: 1_red_room, 2_blue_room, and 3_white_room. In every room, there are many books, every book having: author's_name, title, and text (read from txt files) divided into pages(with numbers).
Given a $word, for every room, the program should list:
room_name, with the overall number of `$word` contexts in all its books
list of authors, who use this word, with number of contexts
for every author, list of books, with number of contexts
for every book, list of pages, with number of contexts
Example of the output:
Word: cucumber
TOTAL: 654
1_red_room: 234
author: John Smith: 70
title: "In the wild": 3
page_50: 1
page_150: 2
title: "Hello world": 10
page_1: 2
page_5: 1
page_7: 3
...
...
2_blue_room: 114
author: Wendy Brown
title: "In the dark": 43
page_8: 7
...
So, is there a way to deal with such data with the help of user-defined classes (or probably using some other instruments)?
Here is how I would start at this. I would create a Book class. Then I would create a hash of books %books for each room:
my $total-count = 0;
my #room-info;
for #rooms -> $room {
my #room-authors;
my %room-authors;
my $room-count = 0;
for #(%books{$room}) -> $book {
my $count = $book.contains-word( $word );
if $count > 0 {
$total-count += $count;
$room-count += $count;
my $author = $book.author;
if %room-authors{$author}:exists {
$(%room-authors{$author}).update($book, $word, $count);
}
else {
%room-authors{$author} = Room-Author.new(
book => $book, word => $word, count => $count
);
#room-authors.push( $author );
}
}
}
if #room-authors.elems > 0 {
#room-info.push(
Room-Info.new(
room => $room, room-count => $room-count,
order => #room-authors, hash => %room-authors
)
);
}
}
say "Word: $word";
say "TOTAL: $total-count";
for #room-info -> $room {
my #room-authors = $room.order;
my %room-authors = $room.hash;
say $room.room ~ " : " ~ $room.room-count;
for #room-authors -> $author-str {
my $author = %room-authors{$author-str};
say " author: " ~ $author.name ~ " : " ~ $author.count;
for #($author.titles) -> $title {
say " title: " ~ $title.title ~ " : " ~ $title.count;
for #($title.pages) -> $page {
say " page_" ~ $page.page ~ ": " ~ $page.count;
}
}
}
}
Here the classes Page, Title, Room-Info, Book, and Room-Author could look like (note: more details must be filled in in real code):
class Page {
has Int $.page;
has Int $.count;
}
class Title {
has Str $.title;
has Page #.pages;
has Int $.count;
}
class Room-Info {
has $.room;
has $.room-count;
has #.order;
has %.hash;
}
class Book {
has Str $.author;
has Str $.title;
has Str $.text;
# checks how many times a word occurs in the book
method contains-word ( $word, --> Int ) {
return 2; # Stub, insert more code here..
}
method get-page-matches( $word ) {
return [Page.new(page => 50, count => 1),
Page.new(page => 150, count => 2)]; # Stub, insert more code..
}
}
class Room-Author {
has Title #.titles;
has Bool %!titles;
has $.name;
has $.count;
submethod BUILD(:$book, :$word, :$!count) {
my $title = $book.title;
$!name = $book.author;
%!titles{$title} = True;
#!titles.push(
Title.new(title => $title,
pages => $book.get-page-matches( $word ),
count => $!count,
)
);
}
method update( $book, $word, $count ) {
my $title = $book.title;
$!count += $count;
my $author = $book.author; # should be the same as $.name..
if %!titles{$title}:exists {
die "Unexpected: Duplicate title '$title' for $author";
}
else {
%!titles{$title} = True;
my Page #pages = $book.get-page-matches( $word );
#!titles.push(
Title.new(title => $title,
pages => $book.get-page-matches( $word ),
count => $count,
) );
}
}
}

Is there a consistent way to test for undefined and null in typescript 2.0? [duplicate]

Since TypeScript is strongly-typed, simply using if () {} to check for null and undefined doesn't sound right.
Does TypeScript have any dedicated function or syntax sugar for this?
Using a juggling-check, you can test both null and undefined in one hit:
if (x == null) {
If you use a strict-check, it will only be true for values set to null and won't evaluate as true for undefined variables:
if (x === null) {
You can try this with various values using this example:
var a: number;
var b: number = null;
function check(x, name) {
if (x == null) {
console.log(name + ' == null');
}
if (x === null) {
console.log(name + ' === null');
}
if (typeof x === 'undefined') {
console.log(name + ' is undefined');
}
}
check(a, 'a');
check(b, 'b');
Output
"a == null"
"a is undefined"
"b == null"
"b === null"
if( value ) {
}
will evaluate to true if value is not:
null
undefined
NaN
empty string ''
0
false
typescript includes javascript rules.
In TypeScript 3.7 we have now Optional chaining and Nullish Coalescing to check null and undefined in the same time, example:
let x = foo?.bar.baz();
this code will check if foo is defined otherwise it will return undefined
old way :
if(foo != null && foo != undefined) {
x = foo.bar.baz();
}
this:
let x = (foo === null || foo === undefined) ? undefined : foo.bar();
if (foo && foo.bar && foo.bar.baz) { // ... }
With optional chaining will be:
let x = foo?.bar();
if (foo?.bar?.baz) { // ... }
another new feature is Nullish Coalescing, example:
let x = foo ?? bar(); // return foo if it's not null or undefined otherwise calculate bar
old way:
let x = (foo !== null && foo !== undefined) ?
foo :
bar();
BONUS
Does TypeScript has dedicated function or syntax sugar for this
TypeScript fully understands the JavaScript version which is something == null.
TypeScript will correctly rule out both null and undefined with such checks.
More
https://basarat.gitbook.io/typescript/recap/null-undefined
I did different tests on the typescript playground:
http://www.typescriptlang.org/play/
let a;
let b = null;
let c = "";
var output = "";
if (a == null) output += "a is null or undefined\n";
if (b == null) output += "b is null or undefined\n";
if (c == null) output += "c is null or undefined\n";
if (a != null) output += "a is defined\n";
if (b != null) output += "b is defined\n";
if (c != null) output += "c is defined\n";
if (a) output += "a is defined (2nd method)\n";
if (b) output += "b is defined (2nd method)\n";
if (c) output += "c is defined (2nd method)\n";
console.log(output);
gives:
a is null or undefined
b is null or undefined
c is defined
so:
checking if (a == null) is right to know if a is null or undefined
checking if (a != null) is right to know if a is defined
checking if (a) is wrong to know if a is defined
You may want to try
if(!!someValue)
with !!.
Explanation
The first ! will turn your expression into a boolean value.
Then !someValue is true if someValue is falsy and false if someValue is truthy. This might be confusing.
By adding another !, the expression is now true if someValue is truthy and false if someValue is falsy, which is much easier to manage.
Discussion
Now, why do I bother myself with if (!!someValue) when something like if (someValue) would have give me the same result?
Because !!someValue is precisely a boolean expression, whereas someValue could be absolutely anything. This kind of expression will now alow to write functions (and God we need those) like:
isSomeValueDefined(): boolean {
return !!someValue
}
instead of:
isSomeValueDefined(): boolean {
if(someValue) {
return true
}
return false
}
I hope it helps.
For Typescript 2.x.x you should do it in a following way(using type guard):
tl;dr
function isDefined<T>(value: T | undefined | null): value is T {
return <T>value !== undefined && <T>value !== null;
}
Why?
In this way isDefined() will respect variable's type and the following code would know take this check in account.
Example 1 - basic check:
function getFoo(foo: string): void {
//
}
function getBar(bar: string| undefined) {
getFoo(bar); //ERROR: "bar" can be undefined
if (isDefined(bar)) {
getFoo(bar); // Ok now, typescript knows that "bar' is defined
}
}
Example 2 - types respect:
function getFoo(foo: string): void {
//
}
function getBar(bar: number | undefined) {
getFoo(bar); // ERROR: "number | undefined" is not assignable to "string"
if (isDefined(bar)) {
getFoo(bar); // ERROR: "number" is not assignable to "string", but it's ok - we know it's number
}
}
I think this answer needs an update, check the edit history for the old answer.
Basically, you have three deferent cases null, undefined, and undeclared, see the snippet below.
// bad-file.ts
console.log(message)
You'll get an error says that variable message is undefined (aka undeclared), of course, the Typescript compiler shouldn't let you do that but REALLY nothing can prevent you.
// evil-file.ts
// #ts-gnore
console.log(message)
The compiler will be happy to just compile the code above.
So, if you're sure that all variables are declared you can simply do that
if ( message != null ) {
// do something with the message
}
the code above will check for null and undefined, BUT in case the message variable may be undeclared (for safety), you may consider the following code
if ( typeof(message) !== 'undefined' && message !== null ) {
// message variable is more than safe to be used.
}
Note: the order here typeof(message) !== 'undefined' && message !== null is very important you have to check for the undefined state first atherwise it will be just the same as message != null, thanks #Jaider.
SIMPLE ANSWER
Although Typescript is a strongly typed language, it has the same problems with pointers and variables initialization inherited from Javascript.
Javascript doesn't check whether a variable exists in the context, the so common undefined status.
to evaluate if value ISN'T null,undefined,0,false,"", or NaN:
if ( value )
or
if ( !!value )
for negative conditional, check if the value is null,undefined,0,false,"",or NaN:
if ( !value )
to test if is null or undefined:
if ( value == null )
to test only null:
if ( value === null )
to test only undefined:
if ( value === undefined )
MORE DETAILED ANSWER
1- It will evaluate to true if value is not: null, undefined, NaN, empty string '', 0, false
If the value is null,undefined,NaN,empty string,0, or false, will go to the else condition.
if ( value ) {
console.log('value is something different from 0, "", false, NaN, null, undefined');
} else {
console.log('value is 0, "", false, NaN, null or undefined');
}
if ( !!value ) {
console.log('value is something different from 0, "", false, NaN, null, undefined');
} else {
console.log('value is 0, "", false, NaN, null or undefined');
}
2- If you want a negative condition, then you'll need to use:
if ( !value ) {
console.log('value is 0, "", false, NaN, null or undefined');
} else {
console.log('value is something different from 0, "", false, NaN, null, undefined');
}
3- It will evaluate if value is null or undefined
if ( value == null ) {
console.log('is null or undefined');
} else {
console.log('it isnt null neither undefined');
}
4- Using a test with boolean values doesn't work.
It will NOT evaluate to true neither to false if value is null, undefined, 0, empty string, NaN
Both conditions will always go to the else condition.
With the exception if value is a boolean variable.
if ( value==true ) {
} else {
}
if ( value==false ) {
} else {
}
if(data){}
it's mean !data
null
undefined
false
....
If you want to pass tslint without setting strict-boolean-expressions to allow-null-union or allow-undefined-union, you need to use isNullOrUndefined from node's util module or roll your own:
// tslint:disable:no-null-keyword
export const isNullOrUndefined =
<T>(obj: T | null | undefined): obj is null | undefined => {
return typeof obj === "undefined" || obj === null;
};
// tslint:enable:no-null-keyword
Not exactly syntactic sugar but useful when your tslint rules are strict.
UPDATE (Sept 4, 2020)
You can now use the ?? operator to validate null and undefined "values" and set a default value. For example:
const foo = null;
const bar = foo ?? 'exampleValue';
console.log(bar); // This will print 'exampleValue' due to the value condition of the foo constant, in this case, a null value
As a verbose way, if you want to compare null and undefined values ONLY, use the following example code for reference:
const incomingValue : string = undefined;
const somethingToCompare : string = incomingValue; // If the line above is not declared, TypeScript will return an excepion
if (somethingToCompare == (undefined || null)) {
console.log(`Incoming value is: ${somethingToCompare}`);
}
If incomingValue is not declared, TypeScript should return an exception. If this is declared but not defined, the console.log() will return "Incoming value is: undefined". Note we are not using the strict equals operator.
The "correct" way (check the other answers for details), if the incomingValue is not a boolean type, just evaluate if its value is true, this will be evaluated according to the constant/variable type. A true string have to be defined explicitly as string using the = '' assignation. If not, it will be evaluated as false. Let's check this case using the same context:
const incomingValue : string = undefined;
const somethingToCompare0 : string = 'Trumpet';
const somethingToCompare1 : string = incomingValue;
if (somethingToCompare0) {
console.log(`somethingToCompare0 is: ${somethingToCompare0}`); // Will return "somethingToCompare0 is: Trumpet"
}
// Now, we will evaluate the second constant
if (somethingToCompare1) {
console.log(`somethingToCompare1 is: ${somethingToCompare1}`); // Launched if incomingValue is defined
} else {
console.log(`somethingToCompare1 is: ${somethingToCompare1}`); // Launched if incomingValue is undefined. Will return "somethingToCompare1 is: undefined"
}
If you are using TypeScript, it is a better approach to let the compiler check for nulls and undefineds (or the possibility thereof), rather than checking for them at run-time. (If you do want to check at run-time, then as many answers indicate, just use value == null).
Use the compile option strictNullChecks to tell the compiler to choke on possible null or undefined values. If you set this option, and then there is a situation where you do want to allow null and undefined, you can define the type as Type | null | undefined.
The simplest way is to use:
import { isNullOrUndefined } from 'util';
and than:
if (!isNullOrUndefined(foo))
We use a helper hasValue that both checks for nulls/undefined and ensures via TypeScript that unnecessary checks are not performed. (The latter is similar to how TS would complain about if ("a" === undefined), since it is always false).
Using this consistently is always safe, unlike !val which matches empty strings, zero, etc. It also avoid the use of fuzzy == matching which is almost always a bad practice - no need to introduce an exception.
type NullPart<T> = T & (null | undefined);
// Ensures unnecessary checks aren't performed - only a valid call if
// value could be nullable *and* could be non-nullable
type MustBeAmbiguouslyNullable<T> = NullPart<T> extends never
? never
: NonNullable<T> extends never
? never
: T;
export function hasValue<T>(
value: MustBeAmbiguouslyNullable<T>,
): value is NonNullable<MustBeAmbiguouslyNullable<T>> {
return (value as unknown) !== undefined && (value as unknown) !== null;
}
export function hasValueFn<T, A>(
value: MustBeAmbiguouslyNullable<T>,
thenFn: (value: NonNullable<T>) => A,
): A | undefined {
// Undefined matches .? syntax result
return hasValue(value) ? thenFn(value) : undefined;
}
Late to join this thread but I find this JavaScript hack very handy in checking whether a value is undefined
if(typeof(something) === 'undefined'){
// Yes this is undefined
}
May be to late! but you can use ?? operator in typescript.
see https://mariusschulz.com/blog/nullish-coalescing-the-operator-in-typescript
You can do this easily with a ternary operator and the new nullish coalesce operator.
First: check to see if it is true using the ternary. If so return false so the if statement does not run.
Second: because you now know the value is falsey, you can use the nullish coalesce operator to return true if it is nullish. Since it will return itself for any other value, if it is not nullish it will fail the if statement correctly.
let x = true;
console.log("starting tests")
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x = false
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x = 0;
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x=1;
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x="";
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x="hello world";
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x=null;
if (x?false:x ?? true){
console.log(x,"is nullish")
}
x=undefined;
if (x?false:x ?? true){
console.log(x,"is nullish")
}
you can use
if(x === undefined)
All,
The answer with the most votes, does not really work if you are working with an object. In that case, if a property is not present, the check will not work. And that was the issue in our case: see this sample:
var x =
{ name: "Homer", LastName: "Simpson" };
var y =
{ name: "Marge"} ;
var z =
{ name: "Bart" , LastName: undefined} ;
var a =
{ name: "Lisa" , LastName: ""} ;
var hasLastNameX = x.LastName != null;
var hasLastNameY = y.LastName != null;
var hasLastNameZ = z.LastName != null;
var hasLastNameA = a.LastName != null;
alert (hasLastNameX + ' ' + hasLastNameY + ' ' + hasLastNameZ + ' ' + hasLastNameA);
var hasLastNameXX = x.LastName !== null;
var hasLastNameYY = y.LastName !== null;
var hasLastNameZZ = z.LastName !== null;
var hasLastNameAA = a.LastName !== null;
alert (hasLastNameXX + ' ' + hasLastNameYY + ' ' + hasLastNameZZ + ' ' + hasLastNameAA);
Outcome:
true , false, false , true (in case of !=)
true , true, true, true (in case of !==) => so in this sample not the correct answer
plunkr link: https://plnkr.co/edit/BJpVHD95FhKlpHp1skUE
Since TypeScript is a typed superset of ES6 JavaScript. And lodash are a library of javascript.
Using lodash to checks if value is null or undefined can be done using _.isNil().
_.isNil(value)
Arguments
value (*): The value to check.
Returns
(boolean): Returns true if value is nullish, else false.
Example
_.isNil(null);
// => true
_.isNil(void 0);
// => true
_.isNil(NaN);
// => false
Link
Lodash Docs
A faster and shorter notation for null checks can be:
value == null ? "UNDEFINED" : value
This line is equivalent to:
if(value == null) {
console.log("UNDEFINED")
} else {
console.log(value)
}
Especially when you have a lot of null check it is a nice short notation.
I had this issue and some of the answer work just fine for JS but not for TS here is the reason.
//JS
let couldBeNullOrUndefined;
if(couldBeNullOrUndefined == null) {
console.log('null OR undefined', couldBeNullOrUndefined);
} else {
console.log('Has some value', couldBeNullOrUndefined);
}
That is all good as JS has no Types
//TS
let couldBeNullOrUndefined?: string | null; // THIS NEEDS TO BE TYPED AS undefined || null || Type(string)
if(couldBeNullOrUndefined === null) { // TS should always use strict-check
console.log('null OR undefined', couldBeNullOrUndefined);
} else {
console.log('Has some value', couldBeNullOrUndefined);
}
In TS if the variable wasn't defined with null when you try to check for that null the tslint | compiler will complain.
//tslint.json
...
"triple-equals":[true],
...
let couldBeNullOrUndefined?: string; // to fix it add | null
Types of property 'couldBeNullOrUndefined' are incompatible.
Type 'string | null' is not assignable to type 'string | undefined'.
Type 'null' is not assignable to type 'string | undefined'.
Usually I do the juggling-check as Fenton already discussed.
To make it more readable, you can use isNil from ramda.
import * as isNil from 'ramda/src/isNil';
totalAmount = isNil(totalAmount ) ? 0 : totalAmount ;
careful if you're using local storage, you can end up with the string undefined rather than the value undefined:
localStorage.setItem('mykey',JSON.stringify(undefined));
localStorage.getItem('mykey') === "undefined"
true
People may find this useful: https://github.com/angular/components/blob/master/src/cdk/coercion/boolean-property.spec.ts
/**
* #license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/** Coerces a data-bound value (typically a string) to a boolean. */
export function coerceBooleanProperty(value: any): boolean {
return value != null && `${value}` !== 'false';
}
import {coerceBooleanProperty} from './boolean-property';
describe('coerceBooleanProperty', () => {
it('should coerce undefined to false', () => {
expect(coerceBooleanProperty(undefined)).toBe(false);
});
it('should coerce null to false', () => {
expect(coerceBooleanProperty(null)).toBe(false);
});
it('should coerce the empty string to true', () => {
expect(coerceBooleanProperty('')).toBe(true);
});
it('should coerce zero to true', () => {
expect(coerceBooleanProperty(0)).toBe(true);
});
it('should coerce the string "false" to false', () => {
expect(coerceBooleanProperty('false')).toBe(false);
});
it('should coerce the boolean false to false', () => {
expect(coerceBooleanProperty(false)).toBe(false);
});
it('should coerce the boolean true to true', () => {
expect(coerceBooleanProperty(true)).toBe(true);
});
it('should coerce the string "true" to true', () => {
expect(coerceBooleanProperty('true')).toBe(true);
});
it('should coerce an arbitrary string to true', () => {
expect(coerceBooleanProperty('pink')).toBe(true);
});
it('should coerce an object to true', () => {
expect(coerceBooleanProperty({})).toBe(true);
});
it('should coerce an array to true', () => {
expect(coerceBooleanProperty([])).toBe(true);
});
});
You could use:
if (!!variable) {}
it equals writting
it (variable != null && variable != undefined) {}
I always write it like this:
var foo:string;
if(!foo){
foo="something";
}
This will work fine and I think it's very readable.