Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Add 'never' type#8652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ahejlsberg merged 6 commits intomasterfromneverType
May 18, 2016
Merged

Add 'never' type#8652

ahejlsberg merged 6 commits intomasterfromneverType
May 18, 2016

Conversation

@ahejlsberg
Copy link
Member

@ahejlsbergahejlsberg commentedMay 17, 2016
edited
Loading

This PR introduces anever type that represents the type of values that never occur. Specifically,never is the return type for functions that never return andnever is the type of variables under type guards that are never true. Thenever type has the following characteristics:

  • never is a subtype of and assignable to every type.
  • No type is a subtype of or assignable tonever (exceptnever itself).
  • In a function expression or arrow function with no return type annotation, if the function has noreturn statements, or onlyreturn statements with expressions of typenever, and if the end point of the function is not reachable (as determined by control flow analysis), the inferred return type for the function isnever.
  • In a function with an explicitnever return type annotation, allreturn statements (if any) must have expressions of typenever and the end point of the function must not be reachable.

Becausenever is a subtype of every type, it is always omitted from union types and it is ignored in function return type inference as long as there are other types being returned.

Thenever type replaces thenothing type introduced in#8340 and it is effectively the same as thebottom type proposed in#3076.

Some examples of functions returningnever:

// Function returning never must have unreachable end pointfunctionerror(message:string):never{thrownewError(message);}// Inferred return type is neverfunctionfail(){returnerror("Something failed");}// Function returning never must have unreachable end pointfunctioninfiniteLoop():never{while(true){}}

Some examples of use of functions returningnever:

// Inferred return type is numberfunctionmove1(direction:"up"|"down"){switch(direction){case"up":return1;case"down":return-1;}returnerror("Should never get here");}// Inferred return type is numberfunctionmove2(direction:"up"|"down"){returndirection==="up" ?1 :direction==="down" ?-1 :error("Should never get here");}// Inferred return type is Tfunctioncheck<T>(x:T|undefined){returnx||error("Undefined value");}

Becausenever is assignable to every type, a function returningnever can be used when a callback returning a more specific type is required:

functiontest(cb:()=>string){lets=cb();returns;}test(()=>"hello");test(()=>fail());test(()=>{thrownewError();})

Fixes#3076.
Fixes#8602.

magicdawn, abbasmhd, ForNeVeR, and x-strong reacted with thumbs up emojizpdDG4gta8XKpMCd, abbasmhd, and x-strong reacted with hooray emojiEyas, zpdDG4gta8XKpMCd, basarat, tinganho, alitaheri, mulyoved, HerringtonDarkholme, ulrichb, stevehansen, headcr4sh, and 8 more reacted with heart emoji
@DanielRosenwasser
Copy link
Member

I really don't think this name is good for the general user experience. My feeling is that it seems to model several different things which the name doesn't reflect very well on. At leastnothing reflected the domain of values a little bit better.

sebnozzi, keyboardDrummer, qc00, felixfbecker, bcherny, tinganho, pietro909, and jan-molak reacted with thumbs up emoji

@ahejlsbergahejlsberg changed the titleAdd 'never typeAdd 'never' typeMay 17, 2016
@ahejlsberg
Copy link
MemberAuthor

ahejlsberg commentedMay 17, 2016
edited
Loading

@DanielRosenwasser The primary use fornever is as the return type of functions that never return. I'm hard pressed to come up with a more concise and descriptive name. Certainlynothing isn't in my mind.

Eyas and Brooooooklyn reacted with thumbs up emoji

@RyanCavanaugh
Copy link
Member

The problem withnothing is that it's very confusing to then say "void is the return type of functions that return nothing".never also parses well with quick info in typeguarded code:

functionf(x:A|B){if(isA(x)){}elseif(isB(x)){}else{x;// appears as type 'never'}}
olydis reacted with thumbs up emoji

@sandersn
Copy link
Member

My objection tonever is that it reads strangely: "f returnsnever" wants to be "f never returns". But "f returnsnothing" reads fine.
It would help to show some examples ofnever actually used in some of the tests.

Other than that, and bike shedding on the name, the code looks good.

sebnozzi, HerringtonDarkholme, keyboardDrummer, and Happi-cat reacted with thumbs up emoji

@DanielRosenwasser
Copy link
Member

Agreed with Nathan - the code looks fine, but I have those gripes with the naming.

@ahejlsberg
Copy link
MemberAuthor

Yes, but "f returnsnothing" also strongly implies thatf actually returns. Which is precisely the intuition we want to avoid!

OG84, keyboardDrummer, dsherret, tomachristian, omariom, kevindqc, Parziphal, bruno-garcia, slavovojacek, lufzle, and 2 more reacted with thumbs up emoji

@sandersn
Copy link
Member

Interesting. That makes it sounds intended that none of the tests explicitly mention their return type isnever. Could we get away with not makingnever a keyword and having it always be inferred?

@ahejlsberg
Copy link
MemberAuthor

No, we can't get away withnever always being inferred. We need it in declaration files, for example. Several of the tests in the PR already explicitly specifynever as their return type.

@sandersn
Copy link
Member

OK, that makes sense. The d.ts is a good enough reason to have the keyword, although I noticed the rest -- outside a d.ts -- are all error cases where the annotation specifies: never and then fails to get it.

@mhegazy
Copy link
Contributor

This will be a breaking change for back compat for .d.ts emit. in the past we inferred the type of these methods/functions asvoid. some one using nightly builds will generate .d.ts files that have the new typenever that is not consumable by TS 1.8 users.

@ahejlsberg
Copy link
MemberAuthor

@mhegazy Yes, but an easy fix is to add avoid type annotation.

@ahejlsbergahejlsberg added this to theTypeScript 2.0 milestoneMay 18, 2016
@mhegazy
Copy link
Contributor

we said we will be more careful in the future with such changes.

@ahejlsberg
Copy link
MemberAuthor

I don't see a big issue here. We're being more precise in our type analysis and that may change the outcome of inference. There are other such issues already resulting from the control flow based type analysis (e.g. narrowing occurs in more places which might affect inferred return types). Effectively we can only replicate the old results by keeping the old code and not changing anything. I think it is reasonable to recommend explicit type annotations if you want to freeze the shape of an API.

@mhegazy
Copy link
Contributor

Being more precise is one issue. Generating a .d.ts that is not consumable is another.

@ahejlsberg
Copy link
MemberAuthor

I'm not sure where you're going with this. What are you proposing?

@yortus
Copy link
Contributor

@ahejlsberg I've just submitted an issue (#8655) about better type analysis aroundassert(...) calls. Could thisnever type be a step toward that kind of analysis becoming possible in future?assert functions might require a return type annotation likevoid | never orx is T | never to tell consumers they either prove a type assertion or don't return at all.

@zpdDG4gta8XKpMCd
Copy link

zpdDG4gta8XKpMCd commentedMay 18, 2016
edited
Loading

Sorry for not minding my own business. The official 1.8. has its *.d.ts fixed and shipped, whoever needs it is welcome to get it anytime. Technically speaking nightly build is 1.9.+ with a bump in the major version number which means breaking changes are likely. Can't see any crime here. People who are scared to break their code are warned to proceed with caution or stay where they are. Am I missing the point?

@kitsonk
Copy link
Contributor

The official 1.8. has its *.d.ts fixed and shipped, whoever needs it is welcome to get it anytime. Technically speaking nightly build is 1.9.+ with a bump in the major version number which means breaking changes are likely. Can't see any crime here. People who are scared to break their code are warned to proceed with caution or stay where they are. Am I missing the point?

It isn't only the TypeScript team that generates.d.ts files. 😄 Meaning that there is a fracture in the entire ecosystem. For example if Angular 2, Dojo 2, RxJS, etc. migrate then it causes them to generate definition files that are not consumable by those that haven't upgraded, continuing to fracture and annoy the wider TypeScript community. Many large entities don't have the time or resources to keep upgrading every 6 weeks.

Both@ahejlsberg and@mhegazy have points. My opinion is if this lands for 2.0, there is thereadonly breaking change. Arguably that is opt-in, while in theory, this would likely end up not being opt-in, but invariably people are going to start producing.d.ts files withreadonly anyways and stranding < 2.0 users. So I would say 2.0 would be the point to break things from an interface perspective.

@kitsonk
Copy link
Contributor

Not quite seeing the issue in the example.

These people (for disclosure, I am the lead for Dojo 2) issue.d.ts which are then consumed by other people to build applications. Your original statement was:

The official 1.8. has its *.d.ts fixed and shipped, whoever needs it is welcome to get it anytime.

But instead of acknowledging that there is potentially more breakage than just what version of thelib.d.ts someone is using, you suggest that project like Dojo 2 (of which I am the lead) can start issuing versions of their.d.ts files without regard for the fact that these projects have a downstream user base. There is a risk with a non-optional breakage like this that we could have serious impacts downstream.

I clearly indicated that both Anders and Mohammad had valid points, of which you seemed to suggest in your original statement confusion about why Mohammad was concerned. I am glad he is concerned. I know both Anders and Mohammad consider downstream projects like Dojo 2 and others in their decisions. Ryan further added though that valid point that this isn't the first breakage of definition files that force the larger community to upgrade. I would argue though that intersection and union types were opt-in, so in theory downstream projects could have chosen not to use them, but they were actually key enablers and so I know we chose to opt-in to them.

Clearly the compromise of emitting avoid in declaration files would be perfect and cause a whole lot less downstream carnage. I am really glad to know that the team thinks about these things instead of going "oh, whats the big deal, people can just upgrade"...

styfle reacted with thumbs up emoji

@zpdDG4gta8XKpMCd
Copy link

you suggest that project like Dojo 2 (of which I am the lead) can start issuing versions of their .d.ts files

Where did I say that?

What I said is: it's a purely engineering problem, and this is what we, engineers, do for living: solve them, and not to seem too arrogant I even outlined how it can be done in typical cases.

Now if the budget of TS is big enough to take on supporting backward compatibility for every team that might benefit of it, I am all for it. Doubtfully so.

More realistically the budget of TS can be better spent on developing new features merits of which far outweigh the troubles of adopting them. And this is what I am rooting for.

Lastly please give an example howv.2.0/lib.d.ts has anything to do withv.1.8/dojo.d.ts?

Elephant-Vessel reacted with thumbs up emojiNemikolh reacted with thumbs down emoji

@ahejlsberg
Copy link
MemberAuthor

I'm not sure generating: void instead of: never in .d.ts files until we ship 2.0 will materially change anything. Aside from appearing to be a bug, it just delays the realization that something has changed. In fact, if we're going to break something then we should break it early in a nightly build to give folks time to adapt. Introducing the actual break right as we ship seems really bad.

We already have a breaking change in 2.0 withreadonly because we sometimes infer it (e.g. when you have a get accessor without a set accessor). I think this one is very similar. I also think it is quite reasonable to ship these changes as long as we document them and the appropriate workarounds.

Alternative solutions are:

  • Never infernever as a return type and instead require an explicit type annotation.
  • Introduce (yet another) switch to enable or disable inference ofnever return types.

I think both of those are worse than just introducing the change. There is real value in having inference producenever as it calls out an important behavioral distinction. We lose that with an opt-in model. And we really don't want more switches.

styfle reacted with thumbs up emoji

@mhegazy
Copy link
Contributor

In#8252 we said we will add this to our "feature checklist". i am just bringing this up as a violation of this.

Given that we rejected the sourceVersion suggestion earlier this weeks, I believe there are two options here, the first is the one you mentioned (that also should apply toundefined andnull now that i think about it), and the second is to say this is too much of a restriction, and it is not supported.
My vote would be for the second.

@ahejlsberg
Copy link
MemberAuthor

Discussed with@mhegazy. We're good with documenting this as a breaking change for .d.ts emit and will also document the workaround (addvoid type annotations).

@ahejlsbergahejlsberg merged commit59f269c intomasterMay 18, 2016
@ahejlsbergahejlsberg deleted the neverType branchMay 18, 2016 19:55
@JsonFreeman
Copy link
Contributor

What a nice feature! I also quite like the name.

@mhegazymhegazy added the Breaking ChangeWould introduce errors in existing code labelMay 20, 2016
@mhegazy
Copy link
Contributor

Note for breaking changes docs:
A common break would be a base class with an implementation to always throws. previously the return was inferred asvoid, now it isnever.

Example:

classBase{method(){thrownewError("Not Implemented!");}}classDerivedextendsBase{method(){return0;}}// error TS2415: Class 'Derived' incorrectly extends base class 'Base'.//   Types of property 'method' are incompatible.//     Type '() => number' is not assignable to type '() => never'.//       Type 'number' is not assignable to type 'never'.

Recommendation:

Give the base class method a type annotation of the expected return type, be itvoid or any other concrete type.

@ahejlsberg
Copy link
MemberAuthor

ahejlsberg commentedMay 23, 2016
edited
Loading

With#8767 we have modified the inference rules to fix the breaking change above. I think we can just consider this a new feature and remove the breaking change label.

@usta
Copy link

usta commentedJun 2, 2016

how about naming it as "impossible" instead of "never"

@kostat
Copy link

kostat commentedJun 2, 2016
edited
Loading

I understand that the primary reason to call the type "never" derives from the desire to facilitate the reading the never returning function declaration. For me, it does not reflect the essence of the type. Look:

var x:never = IAlwaysThrow();

On the other hand the common definition of such code is unreachable code block. Wouldn't it be better to name the type "unreachable"?

function IAlwaysThrow() : unreachable {    throw Error();}var x:unreachable = IAlwaysThrow();

I understand that no one will ever declare a variable of 'unreachable' type, but type is type. When I seevar y:number, I attribute some properties toy. On the same way when I seex:unreachable I understand that I will never reach this point in code. "Never" is close, yet it's uncommon term for this case.

Elephant-Vessel, yvt, and tinganho reacted with thumbs up emoji

@kitsonk
Copy link
Contributor

Considering this is already merged and documented, all we are doing is 🚲 🏠 and navel gazing something is a semantic opinion. The naming was already debated and settled.

RyanCavanaugh, JsonFreeman, and aciccarello reacted with thumbs up emoji

@YowaiCoder
Copy link

What's the point?

@kitsonk
Copy link
Contributor

@fightingcat the point is that TypeScript lacked abottom type and that made it difficult to properly enforce parts of a type system.

@RyanCavanaugh
Copy link
Member

@remojansen please use Stack Overflow for questions -- thanks!

@remojansen
Copy link
Contributor

@RyanCavanaugh sorry my mistake will move it to SO.

@microsoftmicrosoft locked and limited conversation to collaboratorsJun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

No reviews

Assignees

No one assigned

Labels

Breaking ChangeWould introduce errors in existing code

Projects

None yet

Milestone

TypeScript 2.0

Development

Successfully merging this pull request may close these issues.

16 participants

@ahejlsberg@DanielRosenwasser@RyanCavanaugh@sandersn@mhegazy@yortus@zpdDG4gta8XKpMCd@kitsonk@Artazor@JsonFreeman@usta@kostat@YowaiCoder@remojansen@msftclas

[8]ページ先頭

©2009-2025 Movatter.jp