-
-
Notifications
You must be signed in to change notification settings - Fork 11
TypeScript to Dart
This is a work in progress
The ts_ast
app just reads a .d.ts
file and, without too much filtering or business logic at all, dump the analyzed info into a JSON file.
The ts2dart
reads this JSON file and generates an object from a class for each TS declared type in the file, even if the type can not be directly transpiled to Dart.
This strategy consider that the Dart interop may evolve and let us better transpile TS features into Dart code in the future.
Now here is how we handle TS types:
The builder do some logic here to try to find a specific type that we can use, if not, we use dynamic
or Object
by default.
If all types are constants we ditch the union and use an enum instead:
export type Foo = 'one' | 'two';
Becomes an enum:
enum Foo {
one,
two
}
We filter the undefined
or null
to make a nullable type:
export type Foo = Bar | undefined | null;
Transpiles to:
typedef Foo = Bar?;
Everything else becomes dynamic
because we couldn't dissect an specific type definition, ie:
export type Foo = Bar | Daz;
The builder will generate a new type if the intersection is used in typedefs, if not, then dynamic is used.
export type Foo = Bar & Daz;
Transpiles to something like:
class Inline123 implements Bar, Daz {}
typedef Foo = Inline123;
Now when used in arguments:
declare function foo(bar: A & B);
Transpiles to something like:
void foo(dynamic bar);
You can overload a method in TS but not in Dart. The transpiller generates one method for each version so we can still be sound, ie:
interface Document {
createElement<K extends keyof HTMLElementTagNameMap>(tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K];
createElement(tagName: string, options?: ElementCreationOptions): HTMLElement;
}
From the above we generate a Record
called createElement
with two function properties: $1
and $2
.
For the first version ($1
) we identify that the return type is bound to an enum
, thus we can then generate a signature that the return type can be infered:
// div is infered to the type HTMLDivElement
final div = js.document.createElement.$1(js.HTMLElementTagNameMap.div);
The second version in Dart has no difference from the TS one.
A type guard in TypeScript returns a bool
and promotes the argument to that type.
function isFoo(arg): arg is Foo;
When transpiled to Dart, the function returns the nullable type instead:
Foo? isFoo(arg);
void main(arg) {
final foo = isFoo(arg); // foo is of type Foo?
if (foo != null) {
// now foo is of type Foo
}
}
There are complex types that can be directly transpiled to Dart:
- Classes/interfaces
- Typedefs
- Enums
- Tuples
- Functions
There are primitive types, like bool
, that are the same in Dart, you can check the current mappings here.