microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.43k stars 12.42k forks source link

Suggestion: non-nullable type #185

Closed fdecampredon closed 8 years ago

fdecampredon commented 10 years ago

Introduce two new syntax for type declaration based on JSDoc

var myString: !string = 'hello world'; //non-nullable
var myString1: ?string = 'hello world'; // nullable 
var myString2: string = 'hello world'; // nullable 
var myString3 = 'hello world'; // nullable

by default type are nullable.

Two new compiler flag :

var myString3 = 'hello world' // typeof myString is '!string', non-nullable
var myString: !string = 'hello world'; // non-nullable
var myString1: string = 'hello world'; // non-nullable 
var myString2: ?string = 'hello world'; // nullable 
var myString3 = 'hello world' // non-nullable
electricessence commented 10 years ago

I suggest using a type other than string as an example since it by nature is nullable. :P I can perceive non-nullable types being problematic since the user and compiler of "!" expects the type to always be non-null, which can never be truly asserted in JavaScript. A user might define something like this:

function(myNonNull:!myClass):void {
  myNonNull.foo();
}

And because it's defined as non-null, everything might be happy for the compiler, but then someone else who uses it in javascript passes something null and kaboom.

Now that said, maybe the solution could be that for public facing methods, it could automatically assert not null. But then the compiler could also assert that you cannot have public properties (or private for that matter really) that can have a !nonnull declaration since they could not be enforced.

This may go deeper into the discussion of code contracts for this to be properly enforced.

zpdDG4gta8XKpMCd commented 10 years ago

Forgive my critics, I think there is very little need in non-nullable types if/as-soon-as algebraic data types are here. The reason people use null to represent a missing value is because there is no better way to do that in JavaScript and in most OOP languages alike. So imaging ADTs are already here. Then, as for the old libs written before non-nullables, having them won't make life any better. As for the new libs, with ADT's in place one can very accurately model what a value can take according to the business domain specification without using nulls at all. So I guess what I am saying is that ADT is way more powerful tool to address the same problem.

samwgoldman commented 10 years ago

Personally, I just wrote a little Maybe<T> interface and use discipline to ensure that variables of that type are never null.

fdecampredon commented 10 years ago

I suggest using a type other than string as an example since it by nature is nullable. :P I can perceive non-nullable types being problematic since the user and compiler of "!" expects the type to always be non-null, which can never be truly asserted in JavaScript. A user might define something like this:

function(myNonNull:!myClass):void { myNonNull.foo(); } And because it's defined as non-null, everything might be happy for the compiler, but then someone else who uses it in javascript passes something null and kaboom.

I don't really understand you can also define :

function myFunc(str: string): int {
 return str && str.length;
}

and if someone pass an int to that function it will ends up with an error also, an advantage of typescript is to delegate to the compiler pass things that you would check manually in javascript, having another check for nullable/non-nullable type seems reasonable for me. By the way SaferTypeScript and ClosureCompiler already do that sort of check.

fdecampredon commented 9 years ago

With union types, we could have a pretty simpler specification for that. Let's say we have now a basic type 'null', we can have a 'stricter' mode where 'null' and 'undefined' is not compatible with any type, so if we want to express a nullable value we would do :

var myNullableString: (null | string);
var myString = "hello";
myNullableString = myString //valid
myString = myNullableString // error null is not assignable to string;

With the 'strict mode' activated typescript should check that every variable non nullable is initialized, also by default optional parameter are nullable.

var myString: string; // error
var myNullableString: (null | string); // no error

function myString(param1: string, param2?: string) {
  // param1 is string
  // param2 is (null | string)
}
robertknight commented 9 years ago

@fdecampredon +1

IIRC from what Facebook showed of Flow which is using TypeScript syntax but with non-nullable types by default they support a shorthand for (null | T) as in your original post - I think it was ?T or T?.

robertknight commented 9 years ago
var myString: string; // error

That could potentially be quite annoying in the case where you want to initialize a variable conditionally, eg.:

var myString: string;
if (x) {
myString = a;
} else if (y) {
myString = b;
} else {
myString = c;
}

In Rust for example, this is fine as long as the compiler can see that myString will get initialized before it is used but TypeScript's inference doesn't support this at the moment.

fdecampredon commented 9 years ago

Honestly doing something like var myString = '' instead of var myString: string does not bother me so much, but sure that kind of rule is always possible.

johnnyreilly commented 9 years ago

@fdecampredon +1 for this - I like the idea very much. For code bases that are 100% JavaScript this would be a useful compile-time only constraint. (As I understand your proposal there's no intention for generated code to enforce this?)

fdecampredon commented 9 years ago

As for shorthand for (null | string) sure ?string is fine. And sure @johnnyreilly it's only a compile time check

samwgoldman commented 9 years ago

Sum types make non-nullable types by default a very interesting possibility. The safety properties of non-nullable by default can't be overstated. Sum types plus the planned "if/typeof destructuring" (not sure what this should be called) even make it type safe to integrate nullable and non-nullable APIs.

However, making types non-nullable by default is a huge breaking change, which would require changing almost every existing third-party type definition file. While I am 100% for the breaking change, no one person is able to update the type definitions that are out there in the wild.

It's good that a great consensus of these definitions are collected in the DefinitelyTyped repo, but I still have practical concerns about this feature.

fdecampredon commented 9 years ago

@samwgoldman the idea is to have non-nullable types only under a special compiler flag like nonImplicitAny this flag could be named strict or nonNullableType. So there would be no breaking changes.

samwgoldman commented 9 years ago

@fdecampredon What about the type definitions for non-TypeScript libraries, like those at DefinitelyTyped? Those definitions are not checked by the compiler, so any 3rd party code that could return null would need to be re-annotated in order to work correctly.

I can imagine a type definition for a function that is currently annotated as "returns string," but sometimes returns null. If I depended on that function in my nonNullableType'ed code, the compiler doesn't complain (how could it?) and my code is no longer null-safe.

Unless I'm missing something, I don't think this is functionality that can be turned on and off with a flag. It seems to me that this is an all-or-nothing semantic change to ensure interoperability. I would be happy to be proven wrong, though, because I think a flag-switched feature is more likely to happen.

As an aside, there isn't much information available yet on Facebook's Flow compiler, but from the video recording of the presentation, it seems like they went with non-nullable by default. If so, at least there is some precedence here.

fdecampredon commented 9 years ago

Ok let's assume there is a shorthand ? type for type | null | undefined.

@fdecampredon What about the type definitions for non-TypeScript libraries, like those at DefinitelyTyped? Those definitions are not checked by the compiler, so any 3rd party code that could return null would need to be re-annotated in order to work correctly.

I can imagine a type definition for a function that is currently annotated as "returns string," but sometimes returns null. If I depended on that function in my nonNullableType'ed code, the compiler doesn't complain (how could it?) and my code is no longer null-safe.

I don't see the problem, sure some definition files won't be valid with the nonNullableType mode, but most of the time good library avoid to return null or undefined so the definition will still be correct with majority of the cases. Anyway I personally rarely can pick a DefinitelyTyped definition without having to check/modify it you'll just have a little bit of extra work to add a ? prefix with some definitions.

Unless I'm missing something, I don't think this is functionality that can be turned on and off with a flag. It seems to me that this is an all-or-nothing semantic change to ensure interoperability. I would be happy to be proven wrong, though, because I think a flag-switched feature is more likely to happen.

I don't see why we could not have a flag switched feature, the rules would be simple :

Where is the incompatibility with a flag-switched feature ?

RyanCavanaugh commented 9 years ago

Flags that change the semantics of a language are a dangerous thing. One problem is that the effects are potentially very non-local:

function fn(x: string): number;
function fn(x: number|null): string;

function foo() {
    return fn(null);
}

var x = foo(); // x: number or x: string?

It's important that someone looking at a piece of code can "follow along" with the type system and understand the inferences that are being made. If we starting having a bunch of flags that change the rules of the language, this becomes impossible.

The only safe sort of thing to do is to keep the semantics of assignability the same and change what's an error vs what isn't depending on a flag, much like how noImplicitAny works today.

fdecampredon commented 9 years ago

I know it would break retro-compatibility, an I understand @RyanCavanaugh point of view, but after tasting that with flowtype it is honestly really an invaluable feature, I hope it will ends up being a part of typescript

fletchsod-developer commented 9 years ago

In addition to RyanCavanaugh's comment --> From what I read somewhere, the ES7 specification / proposal mention the use of function overloading (Same function name but different input parameter datatype). That is a very sorely needed feature for Javascript.

NoelAbrahams commented 9 years ago

From the flow docs:

Flow considers null to be a distinct value that is not part of any other type

var o = null;
print(o.x); // Error: Property cannot be accessed on possibly null value

Any type T can be made to include null (and the related value undefined) by writing ?T

var o: ?string = null;
print(o.length); // Error: Property cannot be accessed on possibly null or undefined value

[Flow] understands the effects of some dynamic type tests

(i.e. in TS lingo understands type guards)

var o: ?string = null;
if (o == null) {
  o = 'hello';
}
print(o.length); // Okay, because of the null check

Limitations

[D]on't expect a nullable field to be recognized as non-null in some method because a null check is performed in some other method in your code, even when it is clear to you that the null check is sufficient for safety at run time (say, because you know that calls to the former method always follow calls to the latter method).

  • undefined is not checked.

Undefined values, just like null, can cause issues too. Unfortunately, undefined values are ubiquitous in JavaScript and it is hard to avoid them without severely affecting the usability of the language. For example, arrays can have holes for elements; object properties can be dynamically added and removed. Flow makes a tradeoff in this case: it detects undefined local variables and return values, but ignores the possibility of undefined resulting from object property and array element accesses

spion commented 9 years ago

What if the option is added at the same time when introducing the null type (and the questionmark shorthand)? The presence of a null type in a file would force the compiler into non-nullable mode for that file even if the flag is not present at the command line. Or is that a bit too magical?

fdecampredon commented 9 years ago

@jbondc seems good. however the problem with that is that it will ends up with ! everywhere :p

misfo commented 9 years ago
It's tempting to want to change JavaScript but the reality is a 'string' is nullable or can be undefined.

What does this mean? There are no static types in js. So, yes, strings are "nullable", but let's not forget that they are also numberable and objectable and fooable, etc. Any value can have any type.

So when layering a static type system on top of javascript, choosing whether static types are nullable or not is just a design decision. It seems to me non-nullable types are a better default, because it's usually only in special cases that you want a function signature, for instance, to accept a null value in addition to the type specified.

metaweta commented 9 years ago

Directives like "use strict" that cause scoped changes to semantics are already a part of the language; I think it would be reasonable to have a "use nonnullable types" directive in TypeScript.

fdecampredon commented 9 years ago

@metaweta I don't think it's enough, for example what happens if a non null module consume a nullable one :

//module A
export function getData(): string[] {
  return null;
}
//module B
'use nonnull'
import A = require('./A');

var data: string[] = A.getData();

data in module B is in fact nullable, but since 'use nonnull' was not used in module A should we report an error ? I don't see a way to solve that problem with directive based feature.

metaweta commented 9 years ago

Yes,

var data: string[] = A.getData();

would cause an error. Instead, you'd have to provide a default value for when getData() returns null:

var data: string[] = A.getData() || [];
fdecampredon commented 9 years ago

@metaweta ok but how do you know that it's an error ? :) type of getData is still '() => string[]' would you automaticly treat everything that comes from a 'nullable module' as 'nullable ' ?

metaweta commented 9 years ago

Yes, exactly (unless a type from the nullable module is explicitly marked otherwise).

Griffork commented 9 years ago

That sounds like you now want a per file flag that dictates whether of not that file defaults to nullable or not.

Personally I think it's a bit late to introduce this change, and @RyanCavanaugh is right, the change would make Typescript less predictable as you would not be able to determine what was going on just by looking at a file.

Do projects start with this compiler flag on or off by default? If someone is working on a no default nullable project and create / switch to a default nullable one will that cause confusion? I currently work with No Implicit Any in most of my projects, and whenever I come across a project that doesn't have that option turned on it takes me by surprise.

The no impicit any is good, but in terms of flags that change the way the language behaves, I think that should be the line. Any more than that and people who are working on multiple projects started by different people with different rules are going to lose a lot of productivity due to false assumptions and slip ups.

metaweta commented 9 years ago

@RyanCavanaugh was concerned about non-locality, and directives are lexically scoped. You can't get any more local unless you annotate each site. I'm not particularly in favor of the directive; I was just pointing out that the option exists and that it's at least as reasonable as "use strict" in ES5. I'm personally in favor of non-nullable types by default, but practically, it's too late for that. Given those constraints, I'm in favor of using ! somehow. @jbondc 's proposal lets you distinguish null from undefined; given that Java backends continue to make people use both values, it seems the most useful to me.

Griffork commented 9 years ago

I'm sorry if I wasn't clear, I was both agreeing with Ryan and adding my own concerns.

fdecampredon commented 9 years ago

Honestly if adding use not-null is the price for avoiding all the null pointer exception I would pay it without any problem, considering null or undefined as assignable to any type is the worse error that typescript made in my opinion.

Griffork commented 9 years ago

@jbondc I have not used 'use strict' and am therefore making some assumptions, please correct me if my assumptions are wrong:

Not null does not affect the syntax that the programmer writes, but the capabilities of the next programmer that tries to use that code (assuming that creator and user are separate people).

So the code:

function myfoo (mynumber: number) {
    return !!mynumber;
} 

(typing on a phone so may be wrong) Is valid code in both a normal project and a notnull project. The only way that the coder would know whether or not the code is working is if they look at the command line arguments.

At work we have a testing project (which includes prototyping new features) and a main project (with our actual code). When the prototypes are ready to be moved from one project to another (typically with large refractors), there would be no errors in the code, but errors in the use of the code. This behaviour is different to no implicit any and use strict which both would error immediately.

Now I have a fair amount of sway in these projects, so I can warn the people in charge to not use this new 'feature' because it wouldn't save time, but I don't have that capacity over all of the projects at work. If we want to enable this feature in even one project, then we have to enable it in all of our other projects because we have a very significant amount of code sharing and code migration between projects, and this 'feature' would cause us a lot of time going back and 'fixing' functions that were already finished.

metaweta commented 9 years ago

Right @jbondc. @Griffork: Sorry I didn't catch that misunderstanding; a directive is a literal string expression that appears as the first line of a program production or function production and its effects are scoped to that production.

"use not-null";
// All types in this program production (essentially a single file) are not null

versus

function f(n: number) {
  "use not-null";
  // n is not null and local variables are not null
  function g(s: string) {
    // s is not null because g is defined in the scope of f
    return s.length;
  }
  return n.toFixed(2);
}

function h(n: number) {
  // n may be null
  if (n) { return n.toFixed(3); }
  else { return null; }
}
zpdDG4gta8XKpMCd commented 9 years ago

Non-nullable types are useless. Non-nullable types are useles. They are useless. Useless! You don't realize it, but you don't really need them. There is very little sense in restricting yourself by proclaiming that from now on we are not going to be using NULL's. How would you represent a missing value, for example in a situation when you are trying to find a substring that is not there? Not being able to express a missing value (what NULL does now for now) isn't going to solve your problem. You will trade a harsh world with NULL's everywhere for equally harsh one with no missing values at all. What you really need is called algebraic data types that (among many other cool things) feature the ability to represent a missing value (what you are looking for in the first place and what is represented by NULL in imperative world). I am strongly against adding non-nullables to the language, because it looks like useless syntactic/semantic trash that is a naive and awkward solution to a well-known problem. Please read about Optionals in F# and Maybe in Haskell as well as variants (aka tagged unions, discriminated unions) and pattern matching.

metaweta commented 9 years ago

@aleksey-bykov It sounds like you're unaware that JavaScript has two nullish values, undefined and null. The null value in JavaScript is only returned on a non-matching regexp and when serializing a date in JSON. The only reason it's in the language at all was for interaction with Java applets. Variables that have been declared but not initialized are undefined, not null. Missing properties on an object return undefined, not null. If you explicitly want to have undefined be a valid value, then you can test propName in obj. If you want to check whether a property exists on the object itself rather than if it's inherited, use obj.hasOwnProperty(propName). Missing substrings return -1: 'abc'.indexOf('d') === -1.

In Haskell, Maybe is useful precisely because there's no universal subtype. Haskell's bottom type represents non-termination, not a universal subtype. I agree that algebraic data types are needed, but if I want a tree labeled by integers, I want every node to have an integer, not null or undefined. If I want those, I'll use a tree labeled by Maybe int or a zipper.

If we adopt a "use not-null" directive, I'd also like "use not-void" (neither null nor undefined).

zpdDG4gta8XKpMCd commented 9 years ago

If you want to guarantee your own code from nulls just prohibit the null literals. It's way easier than developing non-nullable types. Undefined is a little bit more complicated, but if you know what they are coming from then you know how to avoid them. Bottom in Haskell is invaluable! I wish JavaScript (TypeScript) had a global super type without a value. I miss it badly when I need to throw in an expression. I've been using TypeScript since v 0.8 and never used nulls let alone had a need for them. Just ignore them like you do with any other useless language feature like with statement.

metaweta commented 9 years ago

@aleksey-bykov If I'm writing a library and want to guarantee that inputs are not null, I have to do runtime tests for it everywhere. I want compile-time tests for it, it's not hard to provide, and both Closure and Flow provide support for non-null/undefined types.

zpdDG4gta8XKpMCd commented 9 years ago

@metaweta, you cannot guarantee yourself from nulls. Before your code is compiled there is a gazillion ways to make your lib cry: pleaseNonNullablesNumbersOnly(<any> null). After compiled to js there are no rules at all. Secondly, why would you care? Say it loud and clear upfront nulls are not supported, you put a null you will get a crash, like a disclaimer, you cannot guarantee yourself from all sort of people out there, but you can outline of your scope of responsibilities. Thirdly, I can hardly think of a major mainstream lib that is bulletproof to whatever user may put as input, yet it is still crazy popular. So is your effort worth troubles?

metaweta commented 9 years ago

@aleksey-bykov If my library's clients are also type-checked, then I certainly can guarantee I won't get a null. That's the whole point of TypeScript. By your reasoning, there's no need for types at all: just "say loud and clear" in your documentation what the expected type is.

Griffork commented 9 years ago

Off topic, nulls are extremely valuable for us because checking them is faster than checking against undefined. While we don't use them everywhere, we try to use them where possible to represent uninitialised values and missing numbers.

On topic: We've never had an issue with nulls 'escaping' into other code, but we have had issues with random undefinedes or NaNs appearing. I believe that careful code management is better than a flag in this scenario.

However, for library typings it would be nice to have the redundant type null so that we can choose to annotate functions that can return null (this should not be enforced by the compiler, but by coding practices).

zpdDG4gta8XKpMCd commented 9 years ago

@metaweta, by my reasoning your clients should not use nulls in their code base, it's not that hard, do a full search for null (case sensitive, whole word) and delete all of them. Too clunky? Add a compiler switch --noNullLiteral for fanciness. Everything else stays intact, same code, no worries, way lighter solution with minimal footprint. Back to my point, suppose your non-nullable types found their way to TS and avialable in 2 different flavors:

then you get a piece of json from your server over ajax with nulls everywhere, moral: the dynamic nature of javascript cannot be fixed by a type annotation on top of it

metaweta commented 9 years ago

@aleksey-bykov By the same token, if I'm expecting an object with a numeric property x and I get {"x":"foo"} from the server, the type system won't be able to prevent it. That's necessarily a runtime error and an inescapable problem when using something other than TypeScript on the server.

If, however, the server is written in TypeScript and running on node, then it can be transpiled in the presence of a .d.ts file for my front end code and the type checking will guarantee that the server will never send JSON with nulls in it or an object whose x property is not a number.

zpdDG4gta8XKpMCd commented 9 years ago

@metaweta, non-nullable types sure would be another type safety measure, I am no questioning that, I am saying that by imposing some very basic discipline (avoiding null literals in your code) you can eliminate 90% of your problems without asking for any help from the compiler. Well, even if you have enough resources to enforce this measure, then you still won't be able to eliminate the rest 10% of the problems. So what is the question after all? I ask: do we really need it that bad? I don't, I learned how to live without nulls successfully (ask me how), I don't remember when I got a null reference exception last time (besides in data from our server). There are way cooler stuff I wish we had. This particular one is so insignificant.

spion commented 9 years ago

Yes we do need this badly. See The billion dollar mistake by Hoare. The null pointer exception (NPE) is the most common error encountered in typed programming languages that don't discriminate nullable from non-nullable types. Its so common that Java 8 added Optional in a desperate attempt to battle it.

Modelling nullables in the type system is not just a theoretical concern, its a huge improvement. Even if you take great care to avoid nulls in your code, the libraries you use might not and therefore its useful to be able to model their data properly with the type system.

Now that there are unions and type guards in TS, the type system is powerful enough to do this. The question is whether it can be done in a backward-compatible way. Personally I feel that this feature is important enough for TypeScript 2.0 to be backwards-incompatible in this regard.

Implementing this feature properly is likely to point to code that is already broken rather than break existing code: it will simply point to the functions that leak nulls outside them (most likely unintentionally) or classes that don't properly initialize their members (this part is harder as the type system may need to make allowance for member values to be initialized in the constructors).

This is not about not using nulls. Its about properly modelling all the types involved. Infact this feature would allow the use of nulls in a safe way - there would be no reason to avoid them anymore! The end result would be very similar to pattern matching on an algebraic Maybe type (except it would be done with an if check rather than a case expression)

And this isn't just about null literals. null and undefined are structurally the same (afaik there are no functions/operators that work on one but not the other) therefore they could be modelled sufficiently well with a single null type in TS.

NoelAbrahams commented 9 years ago

@metaweta,

The null value in JavaScript is only returned on a non-matching regexp and when serializing a date in JSON.

Not true at all.

  console.log(window.document.getElementById('nonExistentElement')); // null
 JSON.parse(undefined); // error
 JSON.parse(null); // okay
 JSON.stringify({ "foo" : undefined}); // "{}"
 JSON.stringify({ "foo" : null}); // '{"foo":null}'

NB: We can pretend that undefined is returned via ajax, because accessing a non-existent property will result in undefined - which is why undefined is not serialised.

If, however, the server is written in TypeScript and running on node, then it can be transpiled in the presence of a .d.ts file for my front end code and the type checking will guarantee that the server will never send JSON with nulls in it or an object whose x property is not a number.

This is not entirely correct. Even if the server is written in TypeScipt, one can in no way guarantee nulls from being introduced without checking every single property of every single object obtained from persistent storage.

I kind of agree with @aleksey-bykov on this. While it would be absolutely brilliant if we can have TypeScript alert us at compile time about errors introduced by null and undefined, I fear it will only induce a false sense of confidence and end up catching trivia while the real sources of null go undetected.

Arnavion commented 9 years ago

Even if the server is written in TypeScipt, one can in no way guarantee nulls from being introduced without checking every single property of every single object obtained from persistent storage.

This is in fact an argument for non-nullable types. If your storage can return null Foo's, then the type of the object retrieved from that storage is Nullable<Foo>, not Foo. If you then have a function that returns that is meant to return Foo, then you have to take responsibility by handling the null (either you cast it because you know better or you check for null).

If you didn't have non-nullable types you would not necessarily think to check for null when returning the stored object.

I fear it will only induce a false sense of confidence and end up catching trivia while the real sources of null go undetected.

What sort of non-trivia do you think non-nullable types will miss?

spion commented 9 years ago

This is not entirely correct. Even if the server is written in TypeScipt, one can in no way guarantee nulls from being introduced without checking every single property of every single object obtained from persistent storage.

If the persistent storage supports typed data, then there would be no need. But even if that weren't the case, you'd have checks only at the data fetching points and then have a guarantee throughout all of your other code.

I kind of agree with @aleksey-bykov on this. While it would be absolutely brilliant if we can have TypeScript alert us at compile time about errors introduced by null and undefined, I fear it will only induce a false sense of confidence and end up catching trivia while the real sources of null go undetected.

Using nullable types wouldn't be an absolute requirement. If you feel that its unnecessary to model the cases where a method returns null as they're "insignificant", you could just not use a nullable type in that type definition (and get the same unsafety as always). But there is no reason to think that this approach will fail - there are examples of languages that have successfully implemented it already (e.g. Kotlin by JetBrains)

fdecampredon commented 9 years ago

@aleksey-bykov Honestly you got it completely wrong, one of the best thing about non-nullable types is the possibility to express a type as nullable. With your strategy of never using null to prevent null pointer error you completely loose the possibility of using null out of the fear of introducing error, that's completely silly.

Another thing please in a discussion about a language feature don't go with stupid comments like :

Non-nullable types are useless. Non-nullable types are useles. They are useless. Useless! You don't realize it, but you don't really need them.

That just make me feel like I should ignore whatever you will ever post anywhere on the web, we are here to discuss about a feature, I can understand and gladly accept that your point of view is not mine, but don't behave like a kid.

NoelAbrahams commented 9 years ago

I am not against introducing non-null type annotation at all. It has been shown to be useful in C# and other languages.

The OP has changed the course of the discussion with the following:

Honestly if adding use not-null is the price for avoiding all the null pointer exception I would pay it without any problem, considering null or undefined as assignable to any type is the worse error that typescript made in my opinion.

I was merely pointing out the prevalence of null and undefined in the wild.

NoelAbrahams commented 9 years ago

I should also add that one of the things that I truly appreciate about TypeScript is the laissez-faire attitude of the language. It has been a breath of fresh air.

Insisting that types are non-nullable by default goes against the grain of that spirit.

Griffork commented 9 years ago

I've been seeing a number of arguments floating around as to why we do / don't need this and I want to see if I understand all of the underlying cases that have been discussed such far:

1) want to know whether or not a function can return null (caused by it's execution pattern, not it's typing). 2) want to know if a value can be null. 3) want to know if a data object can contain null values.

Now, there are only two cases in which situation 2 can occur: of you're using nulls or if a function returns a null. If you eliminate all nulls from your code (assuming that you don't want them) then really situation 2 can only occur as a result of situation 1.

Situation 1 I think is best solved by annotating the function's return type to show presence of a null value. This does not mean that you need a non null type. You can annotate the function (for example by using union types) and not have non null types, it's just like documentation, but probably clearer in this case.

Solution 2 is also solved by this.

This allows programmers working at their company to use processes and standards to enforce that null types are marked up, and not the Typescript team (exactly the same way that the whole typing system is an opt-in so would the explicit nullable types be an opt in).

As for scenario 3, the contract between the server and the client is not for Typescript to enforce, being able to mark-up the affected values as possibly null might be an improvement, but eventually you'll get the same garentee from that as typescript's tooling gives you on every other value (which is to say, none unless you have good coding standards or practices!

(posting from phone, sorry for errors)