Typescript to Scala.js converter
This is a packed release 🚀 , with bug fixes going back months as well as significant encoding changes.
Due to the scala-xml situation only sbt 1.8.x is supported now.
Note that due to a bug in scalajs-bundler you'll also have to upgrade it to 0.21.1
if you use it.
Read about it here #485 , it's an effort to make the encoding more transparent.
Basically it will require you to go through your code base and perform this maneuver:
If you're not ready to do it right away, add stShortModuleNames := true
(for sbt plugin) and --shortModuleNames
for CLI. This will keep the old behaviour.
Note that it's expected that windows users will face some problems after this change, since paths will be longer on average. Some of the other changes in the release are motivated by working towards shorter source and class file names.
js.Promise
Sorry, but it's impossible to do it in inheritance clauses, so that was taken out. Instead references to std.Promise
is generated, and you get syntax for it. Implemented in f514ce01 .
val p: std.Promise[Int] = ???
val p2: js.Promise = p.toPromise
val p3: Future = p.toFuture
if you references things inside ...libNumbers
you'll now have to reach into ...libDoubles
and ...libInts
instead.
Some unrepresentable or very long literals are now widened to String
or Double
. Fake literals end up as java class files, and they should ideally not be too long given windows' max path length.
Implemented in 7cb11a78
This is a newish concept for exposing javascript modules on names which do not match file path, it also works for hiding modules inside a package. This enables multiple "big" libraries to work much better with ST, primarily firebase.
Implemented in #367
The functionality in ST which calculates for instance which methods should be added to "complete" a class given that it extends from interfaces where fields and methods are left without an implementation didn't really work with abstract classes. These hierarchies can be awfully deep, and there are loads of edge cases.
Given that this would require difficult changes to ST to fix, and since this functionality is so rarely used in Typescript, the entire concept is just replaced by a comment for now. The user can then do the right thing and implement what's missing. Implemented in baf58e88 .
- @JSImport("aws-sdk/lib/config_service_placeholders", "ConfigurationServicePlaceholders")
- @js.native
- abstract class ConfigurationServicePlaceholders () extends StObject {
+ /* note: abstract class */ @JSImport("aws-sdk/lib/config_service_placeholders", "ConfigurationServicePlaceholders")
+ @js.native
+ open class ConfigurationServicePlaceholders () extends StObject {
-type Proxify[T] = /* import warning: importer.ImportType#apply c Unsupported type mapping:
-{[ P in keyof T ]: {get (): T[P], set (v : T[P]): void}}
- */ typings.typeMappings.typeMappingsStrings.Proxify & TopLevel[Any]
+/** NOTE: Mapped type definitions are impossible to translate to Scala.
+ * See https://www.typescriptlang.org/docs/handbook/2/mapped-types.html for an intro.
+ * You'll have to cast your way around this structure, unfortunately.
+ * TS definition: {{{
+ {[ P in keyof T ]: {get (): T[P], set (v : T[P]): void}}
+ }}}
+ */
[email protected]
+trait Proxify[T] extends StObject
These are also untranslatable. However, in conditional types there is frequently some base case, which often is useful from Scala.
As such there is functionality to pick out this base case as an approximation. Note that the approximation part is not new per se, but it's improved.
/**
* Exclude from T those types that are assignable to U
*/
/** NOTE: Conditional type definitions are impossible to translate to Scala.
* See https://www.typescriptlang.org/docs/handbook/2/conditional-types.html for an intro.
* This RHS of the type alias is guess work. You should cast if it's not correct in your case.
* TS definition: {{{
T extends U ? never : T
}}}
*/
type Exclude[T, U] = T
/** NOTE: Conditional type definitions are impossible to translate to Scala.
* See https://www.typescriptlang.org/docs/handbook/2/conditional-types.html for an intro.
* You'll have to cast your way around this structure, unfortunately.
* TS definition: {{{
R extends react.react.Reducer<any, infer A> ? A : never
}}}
*/
@js.native
trait ReducerAction[R /* <: Reducer[Any, Any] */] extends StObject
Implemented in 28eaaada, 10e2ae1a, e94a5f3c and 424fb031
Given typescript code
export declare const rectWithPoints: ({ x: x1, y: y1 }: Coordinate, { x: x2, y: y2 }: Coordinate) => {
x: number;
y: number;
width: number;
height: number;
};
- inline def rectWithPoints(hasX1Y1: Coordinate, hasX2Y2: Coordinate): Height = (^.asInstanceOf[js.Dynamic].applyDynamic("rectWithPoints")(hasX1Y1.asInstanceOf[js.Any], hasX2Y2.asInstanceOf[js.Any])).asInstanceOf[Height]
+ inline def rectWithPoints(param0: Coordinate, param1: Coordinate): Height = (^.asInstanceOf[js.Dynamic].applyDynamic("rectWithPoints")(param0.asInstanceOf[js.Any], param1.asInstanceOf[js.Any])).asInstanceOf[Height]
This is because the names could become unwieldy long, and would in some cases end up names of java class files. Implemented in 21ff172c
ST is now built in CI on linux, mac and windows. To get the tests running, a bunch of improvements to consistency (= ST always outputs exactly the same code, and digests it to the same hash) was needed.
This will greatly benefit anyone using windows, as your builds now have the same digest as your friends / colleagues. It will also benefit anyone wanting to contribute to ST from windows, as tests will now run clean on your machine.
Implemented in #500.
While not user-facing, it's also significant that the Distribution build is ran every night, with all the newest versions of libraries. Before libraries were generally out of date, because it's very difficult to make npm
or yarn
upgrade 10k packages. This was fixed in #477.
This way, the effect of a commit on master can be seen clearly:
Currently it stands at 12821 successfully imported libraries, and 92 failing (plus whatever is downstream of those).
In total, all these improvements add up to hundreds of newly supported libraries
Full Changelog: https://github.com/ScalablyTyped/Converter/compare/v1.0.0-beta39...v1.0.0-beta40
This bumps the sbt version necessary to 1.7.x. This was necessary since the vulnerable okhttp 3 library, which used to be shipped with sbt, was used in the ScalablyTyped sbt plugin. See https://github.com/sbt/librarymanagement/pull/399 for details
While ST should work with older versions, there are no tests to ensure it works. For that reason it's strongly recommended to stay current.
Upgrading to scala-js-dom 2.0.0 requires migration, see release notes. Note that ST only supports one version of scala-js-dom, so to use 1.0.0-beta37 you need to upgrade.
Done in #377
If you use scalajs-react it has also seen a major release, so your code may require some migration for that as well. Again see release notes
Note again that ST only supports one version of scalajs-react, so to use 1.0.0-beta37 you need to upgrade.
On the bright side you get Scala 3 support. Have a look at the demo projects which are ported to scala 3, including new syntax.
Done in #326
Any
instead of js.Any
See #351 . This might require some tweaks to your code, but it should just be changing the latter to the former. Usage of js.Any
remains in some places, like when interacting with js.Dynamic
.
If you use stUseScalaJsDom := false
(not default) some types are now rewritten from std
to types in scalajs-library, for instance js.Error
and typed arrays. See #372 .
-source:future
- see #364 . The most visible thing is that classes are now open
.csstype
, which is a dependency of react. The issue was an intersection type with js.Object
and String
. Fixed in https://github.com/ScalablyTyped/Converter/commit/f4451cf97116588db41791227ef86a71afe6ae11
If you use the slinky flavour, you'll need to update. There shouldn't be any migration required. ST will now use the Scala 3 artifact of slinky-web
for Scala 3, and will generate working code. However, if you want to upgrade keep in mind that all the @react
syntax is missing in Scala 3 so far.
This is fairly untested, but it seemed to be binary compatible with 1.5.x .
std
standard libraryFor now these are just comments. If they are useful for tooling, perhaps they could become annotations down the line.
@js.native
trait Map[K, V] extends StObject {
/* standard es2015.collection */
def clear(): Unit = js.native
/**
* Returns an iterable of key, value pairs for every entry in the map.
*/
/* standard es2015.iterable */
def entries(): IterableIterator[js.Tuple2[K, V]] = js.native
/* standard es2015.collection */
def forEach(callbackfn: js.Function3[/* value */ V, /* key */ K, /* map */ Map[K, V], Unit]): Unit = js.native
def forEach(callbackfn: js.Function3[/* value */ V, /* key */ K, /* map */ Map[K, V], Unit], thisArg: js.Any): Unit = js.native
/** Returns an iterable of entries in the map. */
/* standard es2015.iterable */
@JSName(js.Symbol.iterator)
var iterator: js.Function0[IterableIterator[js.Tuple2[K, V]]] = js.native
/* standard es2015.symbol.wellknown */
@JSName(js.Symbol.toStringTag)
val toStringTag: java.lang.String = js.native
}
30 Øyvind Raddum Berg
11 Scala Steward
2 Hugo van Rijswijk
1 Ingar Abrahamsen
1 nafg
Especially useful for generating libraries, you can now mark all the generated code as private within a package, see docs for stPrivateWithin
It'll look like this:
package mylib.internal.baz.materialUi
import japgolly.scalajs.react.raw.React.Component
import org.scalablytyped.runtime.StObject
import scala.scalajs.js
import scala.scalajs.js.annotation.{JSGlobalScope, JSGlobal, JSImport, JSName, JSBracketAccess}
private[internal] object MaterialUI {
...
}
extension
and inline
for Scala 3 code (#335)This is just syntactic, but really does clean up code:
[email protected]
- implicit class APIVersionsMutableBuilder[Self <: APIVersions] (val x: Self) extends AnyVal {
-
- @scala.inline
- def setApiVersion(value: latest | String): Self = StObject.set(x, "apiVersion", value.asInstanceOf[js.Any])
+ extension [Self <: APIVersions](x: Self) {
+
+ inline def setApiVersion(value: latest | String): Self = StObject.set(x, "apiVersion", value.asInstanceOf[js.Any])
export namespace as
Quite a few libraries were missing the globally available version of the typings because this typescript construct was not implemented.
devDependencies
as well (#339, 88ec013bd6d8ba9eaa58ec127d273396dd91dbf4)This needs to be enabled by stIncludeDev
Drops support for sbt 1.4 and only allows 1.5, Also upgrades to scala-js-dom 1.2, Scala.js 1.7.0
The translation of method definition in ST relies on splitting methods into more methods on union types. Given this:
export const foo = (bar: 'a' | ' b' | number) => number
This used to be translated like this:
def foo_a(bar: a): Double // using the fake literal types encoding
def foo_b(bar: b): Double
def foo(bar: Double): Double
Now it'll be translated to this instead:
def foo(bar: a | b): Double // using the fake literal types encoding
def foo(bar: Double): Double
This is somewhat experimental, and is meant to be a step on the way towards cleaner method signatures and true literal types.
ST has some logic for deduplicating types which are exported and reexported between modules by only keeping the original version, this is done to avoid ambiguity errors and to reduce the total number of generated types. Some re-exported types slipped through the net, and are now not generated anymore. If this affects you you should be able to delete the import and import whatever the IDE suggests instead.
32 Øyvind Raddum Berg
2 Scala Steward
1 Alexis Hernandez
1 Arman Bilge
@ScalaJSDefined
) by default for Scala 3See Scala.js documentation for details. This has been possible to enable with stEnableScalaJsDefined, but it has been disabled because compilation is very very slow with Scala 2.x. For Scala 3 this is now enabled for all libraries by default.
Quite a few see full changelog for details
After months of prep-work (and a few compiler bugs) the converter now works with Scala 3 :partying_face:
React users likely cannot update yet, since neither scalajs-react nor Slinky works with Scala 3 yet.
The demo repository is updated, and it'll soon see a style update as well in https://github.com/ScalablyTyped/Demos/pull/25 .
Libraries with more than 6000 files can only be compiled with Scala 3.0.1 and up, which is due for release any day now. You'll see a StackOverflowError
if this affects you.
In a lot of places js.Any
was rewritten to _
to make some patterns a bit smoother, primarily to pretend like types were covariant.
This is an example of generated before/after
@js.native
trait RefProps extends StObject {
var children: Element = js.native
- var innerRef: Ref[_] = js.native
+ var innerRef: Ref[js.Any] = js.native
}
Before you could do this:
val ref: Ref[Foo] = ???
val refProps: RefProps = ???
refProps.innerRef = ref
And after you'll have to cast to make the last statement work
refProps.innerRef = ref.asInstanceOf[Ref[js.Any]]
This is clearly unfortunate, but existential types are sufficiently different (and limited) in Scala 3 that no path forward was found here. More work could be done in this direction, however.
This is not user facing, but it means that the set of generated methods will vary slightly in the presence of many overloads.
A type parameter for reference had to be added to (the implicitly called) StBuildingComponent.make
for Scala 3. Some react components have type parameters, and in some cases those will be inferred to be Nothing
. When that happens an explicit .build
is needed with Scala 2.
// part of a generated component which is polymorphic both in props and element
object TileLayer {
def apply[P /* <: TileLayerProps */, E /* <: TileLayer_ */](p: P): Builder[P, E] = new Builder[P, E](js.Array(this.component, p.asInstanceOf[js.Any]))
// use component. unless explicitly set, `E` ends up as `Nothing`
TileLayer(
TileLayerProps(url = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
.setAttribution("© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors")
),
Now you'll need to say TileLayer(...).build
. This should be fixed in a future release
The generated code is 99% the same across scala versions after this change, except for
js.|
and with
This diff shows typical differences:
-package typings
+package typings.node
import org.scalablytyped.runtime.StObject
import scala.scalajs.js
-import scala.scalajs.js.`|`
import scala.scalajs.js.annotation.{JSGlobalScope, JSGlobal, JSImport, JSName, JSBracketAccess}
-package object node {
type Foo = typings.node.NodeBuffer | String
-}
26 Øyvind Raddum Berg
5 Scala Steward
Bintray is shutting down, and that had been used extensively for ScalablyTyped. Some details in #262 , but most importantly:
ClassDefNotFoundError
or similar in sbt you're affected. More details in #271plugins.sbt
.resolvers += MavenRepository("sonatype-s01-snapshots", "https://s01.oss.sonatype.org/content/repositories/snapshots")
. All master builds publish snapshotsthis
object RadioProps {
@scala.inline
- def apply(name: String, `type`: radio): RadioProps = {
- val __obj = js.Dynamic.literal(name = name.asInstanceOf[js.Any])
- __obj.updateDynamic("type")(`type`.asInstanceOf[js.Any])
+ def apply(name: String): RadioProps = {
+ val __obj = js.Dynamic.literal(name = name.asInstanceOf[js.Any])
+ __obj.updateDynamic("type")("radio")
__obj.asInstanceOf[RadioProps]
}
T | Null
members (710eff04, 7adc999f) @js.native
trait ReactElement extends StObject {
var key: Key | Null = js.native
var props: js.Any = js.native
var `type`: String | ComponentClassP[js.Object] | SFC[_] = js.native
}
object ReactElement {
@scala.inline
def apply(props: js.Any, `type`: String | ComponentClassP[js.Object] | SFC[_]): Element = {
- val __obj = js.Dynamic.literal(props = props.asInstanceOf[js.Any])
+ val __obj = js.Dynamic.literal(props = props.asInstanceOf[js.Any], key = null)
__obj.updateDynamic("type")(`type`.asInstanceOf[js.Any])
__obj.asInstanceOf[Element]
}
@expo/vector-icons
(6de2dc97)- type DOMFactory[P /* <: typingsJapgolly.react.mod.DOMAttributes[T] */, T /* <: org.scalajs.dom.raw.Element */] = js.Function2[
- /* props */ js.UndefOr[(typingsJapgolly.react.mod.ClassAttributes[T] with P) | scala.Null],
- /* repeated */ japgolly.scalajs.react.raw.React.Node,
- japgolly.scalajs.react.raw.React.DomElement
- ]
[email protected]
+trait DOMFactory[P /* <: DOMAttributes[T] */, T /* <: Element */] extends StObject {
+
+ def apply(props: ClassAttributes[T] with P, children: Node*): DomElement = js.native
+ def apply(props: js.UndefOr[scala.Nothing], children: Node*): DomElement = js.native
+ def apply(props: Null, children: Node*): DomElement = js.native
+}
Added Working with objects
26 Øyvind Raddum Berg
11 Scala Steward
1 povder