Type annotations
Main challenge of TypeScript annotations is that there is no type inference like F# (constraint solving), only type checking. So if there is an uninitialized variable like var x;, it will have type any unless annotated: var x: number;. Just having typed signature but under-typed implementation leads to many different type check errors. Method signatures are already in place, so there are further tasks for having correctly typed TypeScript output:
- [ ] 1) Convert WebSharper's
runtime.jsto TypeScript - [x] 2) Add types to translations of module
letvalues - [x] 3) Create separate TS interfaces for F# union cases. Full type of the union
type MyUnion = X of int | Y of stringwould betype MyUnion = MyUnion.Class & (MyUnion.X | MyUnion.Y)whereMyUnion.Xis defined with{ $:0; $1:number }(form of unions in WS runtime) - [x] 4) Whenever a string/array is converted to an
IEnumerable, wrap it in aStringEnumerator/ArrayEnumeratorimmediately, instead of handling translation ofGetEnumeratorspecially - [ ] 5) local variables should not be collected on top of function scope any more, but defined with
let/const(#816) so that TS type inference can resolve their types. - [ ] 6) Types with
Prototype(false)should translate to a TS interface, declaring the types of the properties (values are plain objects). - [x] 7) Tuple types are never inferred, only arrays:
[1, "hi"]will be taken as an(number | string)[]instead of[number, string]. So type annotations are needed:<[number, string]>[1, "hi"]for creating tuples. Details in #822 - [x] 8) Allow the
Typeattribute on generic parameters to specify that only types are allowed that translate or is compatible with a specific TS type. For example, onSeq.averageproxy, the result is always anumberbut it is generic in .NET. If the proxy would define it likelet Average<[<Type "number">] 'T> (s: seq<'T>) : 'T, then WebSharper would know that in TS, it can erase theTtype parameter and have it translate tonumber, also throw a compiler error when it is used with a type that is not mapped tonumber. - [x] 9) Transform checks against interfaces to a function that returns a user-defined type guard.
- [x] 10) Transform delegate types. Details at #824
- [ ] 11) (optional) Print consts for enum cases, have a type alias for them (just aliasing
number) - [x] 12) Map types of 2-dimensional arrays
On 4):
Original description: Translate the IEnumerable types to an union of IEnumerable<T> | T[] | string (because WS enumeration can handle arrays and strings specially)
To not have a messy type for IEnumerables, it is easier to have them translate directly to the interface type. This needs a runtime change in the handling of enumerating on strings and arrays: instead of a runtime type check at the point of the GetEnumerator call, wrap strings and arrays where they are converted to a sequence into StringEnumerator/ArrayEnumerator helpers that implement GetEnumerator.
-
Needs some more casts for accessing
thiswithin members of the union class as a strongly typed union (in TS, a union of cases). Type checks has to be translated against the class type, not the combined union type. -
Was solved by extending built-in Array and String to have
GetEnumerable. Need to set the prototypes inWebSharper.Main.ts.
-
We can't rely on type inference to resolve the type of every
varbecause WebSharper might need to print uninitialized variables. The type of every local variable will be persisted, so thatvar/letdeclarations without assignment can have the type annotation. -
Type annotations will not be stored for lambdas but tuple value creation because they are the underlying cause for this error. A tuple will be always translated with type annotations, like
<string, number>["hello", 3].