Description
Narrowing within Function Expressions
const
Modifiers on Function Parameters
functin f0() {
let x = getStringOrNumber();
if (typeof x === "string") {
const f = () => x.length; // currently errors
}
}
- We don't make an effort to dive within functions expressions - we don't narrow within them.
- However, when you have a
const
, you know for sure that you can definitely narrow. - We're making sure that works.
- Problem is, you can't reflect that behavior with parameters today.
- However, when you have a
- In a constructor can you have a
public const
?- We could say
public readonly
does that?- That's conflating the idea.
- "It's uninteresting" and doesn't come up in practice
- We could say
- What about nested members of a
const
?-
i.e.
const x = { foo: { bar: number } }; x.foo.bar;
-
IIFEs
Repro from #8381
(function() {
}())
- Look at the PR
Enums & Algebraic Data Types
-
Simple approach is that you use singleton value types.
-
Currently, these singleton value types are limited to string literal types.
type Foo = "up" | "down"; var x: Foo; switch (x) { case "up": // ... break; case "down": // ... break; }
-
Gets more interesting with something like:
interface Up { kind: "uP"; speed: number; } interface Down { kind: "down"; fatal: boolean; } var x: Up | Down; switch (x.kind) { case "up": x.speed; break; case "down": x.fatal; break; }
- Forgive the terrible example.
-
These need not be string literals - they could be numbers, enums.
-
Wouldn't it be nice if we could do this sort of thing with
SyntaxKind
in the compiler?-
Each node would define its own specific discriminator in its
kind
field.interface Node { kind: SyntaxKind; } interface PropertyAccess { kind: SyntaxKind.PropertyAccess; }
-
Problematically, you couldn't quite do this with the OO-style property inheritance we get (open-ended in OOP, close-ended in FP).
-
Ideally, you could do exhaustiveness checking with this, but
Node
is open-ended right now.-
So you'd do something like this:
interface NodeBase { kind: SyntaxKind; } interface PropertyAccess { kind: SyntaxKind.PropertyAccess; } interface CallExpression { kind: SyntaxKind.CallExpression; } type Node = PropertyAccess | CallExpression // | ...
-
What would the type of a
Node
's kind be now?-
SyntaxKind.ProperyAccess | SyntaxKind.CallExpression | ....
-
Is
SyntaxKind
equivalent to that union type? -
Not necessarily! That can be confusing!
-
So you'd have to do something like this:
const enum Color { Red, Green, Blue } type AllColors = Color.Red | Color.Green | Color.Blue;
-
-
-
-
-
So to avoid the
AllColors
example, you could imagine that we'd have a new kind of enum:union enum Color { Red, // 0 Green, // 1 Blue // 2 }
- Couldn't use flags in this example.
-
TC39 convo on enums had symbols in mind.
- Issues with that.
- Need to be able to serialize that in an error message.
- Issues with that.
-
DR: I think we could do ADT-style stuff without needing enum types yet.
- AH: Yes, and strings are fine, but you really can't do that with numbers.
- DR: But ADTS are moe general.
- AH: But string/number discriminators are the real value of this feature.
- DR: Agreed.
-
DR: Problem is that the base-type/intermediate-types/union-type pattern is cumbersome - you've fixed the enum type, done nothing there.