-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Special bottom
type
#3076
Comments
It's obviously related to the #1613 |
Also related to removing 'void' from a union type and allowing its use as a type guard #1806 Still find it odd that number|void doesn't collapse to -> number. |
I think that bottom !== void and we can not collapse number|void to number because it represents the state where value is either number or undefined, meanwhile the number means a guaranted number. Um? |
What do you mean? A number type can have values 'null' or 'undefined', a void type can have values 'null' or 'undefined'. A void type is clearly a subset of the number type, it's redundant in a union. |
I think that you are wrong, but the explanation is tricky. This is the consequence of the "carefully corrupted" type system by @ahejlsberg. null and undefined values are assignable to the number not because of they are part of the numbers domain. They are assignable because of an explicit ad-hoc rule (their type is function(a: number) {
return a.toExponential();
} will fail when it is called with null or undefined. type number is not a strict guarantee that the value is a number, it is a hint that in normal circumstances it should be a number. If you purposely pass the null value to it, then you probably know what you do. In opposite (number|void) says that it is normal to expect an "undefined" value. @ahejlsberg, am I right? |
I think that it implicitly correlates with the I'd say that
where "throw" statement is actually an expression of type bottom |
Since TS has no model for exceptions in the type system, I think this workaround would be nice. Other than the unions rule, I'm assuming it would behave the same as I don't like |
@Artazor Not sure if there's a right or wrong about 'void' at the moment, it's just ambiguous:
We do agree there should be a bottom type, in my world I call it void!null!undefined. |
@jbondc your type exclusion syntax is very relevant (have you proposed the syntax itself anywehere?) I'd say that type Bottom = number!number // or any other type Nevertheles, both var x:string = null // ok
var y:string = (() => null)() // ok (any is propogated outside)
var z:string = (():void => null)() // error: can't assign void to string Hard decision to type the UPD x => void f() for example
Has type |
what is wrong with defining alwaysThrow as follows: function alwaysThrow<a>() : a { throw new Error(''); } it works immediately without requiring the presence of the bottom type which, unfortunately, needs runtime support from javascript to be what it is |
@Aleksey-Bykov hm? I'm talking about purely static type inference.The primary goal for the bottom type is preventing pollution of union types when inferred implicitly. If I understood your suggestion correctly you are talking about writing function test(a: boolean) {
return a ? 123 : alwaysThrows<number>();
} This, unfortunately, kills the idea of type inference (or at least seriously affects its reputation). |
Exactly. But you can pass this type to anywhere, because of in real life this passing will never happen because of the exception already thrown.
Here I don't understand. I think the rule of (void | T = void) is very dangerous and irrelevant. Can you elaborate why you ever thought that it would be useful? I think that this discussion lacks people from the actual TS team, @mhegazy? |
Anyway, now I start to think that bottom type should have no name at all. It should be inferred statically. function parseAndThrow(errorInfo: IErrorInfo) throw {
...
} This is a limited and the strongest form of the checked exceptions which states that the function always throws. And it can be implemented without checked exceptions machinery at all - it simply needs the bottom type internally. |
@jbondc excluding would be nice, also I would highly anticipate the intersection type, for the immediate intersection of interfaces: var x: IMyInterface & IRunnable In fact, I would be happy if TypeScript would have the following type structure: (I've mentioned this already in petkaantonov/bluebird#589) The Type Systemof my dream for TypeScriptτ ::= tcon | α | (τ τ) | (Λα.τ) | (τ → τ) | (τ × τ) | ⊤ | ⊥ | (τ ⋂ τ) | (τ ⋃ τ) | (!τ) | (τ ^ τ) where
This system has usual parentheses elimination conventions and two aliases:
Checked exceptions (τresult ^ τerror) have two simple properties:
that makes (τ ^ τ) associative. (there are more rules, of course) |
@Artazor Do you have examples of use cases for type negation? Never seen that before, which programming language? |
I guess:
It doesn't seem too difficult to implement, you just pluck it out of your set of union types. |
@Artazor I meant |
The |
@weswigham exactly! The bottom type was proposed to reflect the result of the control flow analysis, and surely could not be implemented without proper CFA, which now is available. Isn't it? |
I think that it should be special bottom type with the following properties:
two functional types are not assignable to each other if exactly one of them has return type bottom(?);rationale
Let's consider the function that always throws:
and other function that uses it
We expect that
test
should have typenumber
instead of( number | void )
In more sophisticated example that involves Promise type declarations:
We expect that
should have the type of
Promise<string>
instead ofPromise<string | void>
.See petkaantonov/bluebird#589 (comment)
Possible explicit annotation that function always throws is using undefined as the type
The text was updated successfully, but these errors were encountered: