diff --git a/docs/advanced/language-extensions.md b/docs/advanced/language-extensions.md index c54fe7cf..2f4194f1 100644 --- a/docs/advanced/language-extensions.md +++ b/docs/advanced/language-extensions.md @@ -60,3 +60,79 @@ function myFunc(self) end foo, four = myFunc(nil) ``` + +## Operator Map Types + +Lua supports overloading operators on types using [metatable methods](https://www.lua.org/manual/5.4/manual.html#2.4) such as `__add`. But, Javascript and Typescript do not support this. In order to use overloaded operators on types that support them, you can declare special mapping functions in TS that will translate to those operators in Lua. + +A common example of an overloaded operator is addition of a mathematical vector type: + +```ts +// Vector type supplied by a library, which supports math operators +declare interface Vector { + x: number; + y: number; +} + +declare const a: Vector; +declare const b: Vector; +const result = a + b; // Not allowed in TS +``` + +To support addition for this type, you can declare a special function: + +```ts +declare const addVector: LuaAddition; +const result = addVector(a, b); // transpiles to 'result = a + b' +``` + +The mapping function does not have to be declared as global. For example, you could use declaration merging to declare it as a static function on `Vector`: + +```ts +declare namespace Vector { + export const add: LuaAddition; +} + +const result = Vector.add(a, b); // result = a + b +``` + +There are also special variants for the mapping types that allow you do declare operator overloads as methods: + +```ts +declare interface Vector { + add: LuaAdditionMethod; +} +const result = a.add(b); // result = a + b +``` + +Some operators may have a different return type based on their inputs. You can support this by using intersection types. For example, our `Vector` type might overload the multiplication operator to scale by a number, or perform a dot product on two `Vectors`: + +```ts +declare namespace Vector { + export const mul: LuaMultiplication & LuaMultiplication; +} + +const dot: number = Vector.mul(a, b); +const scaled: Vector = Vector.mul(a, 2); +``` + +### Supported Operators: + +- Math operators + - LuaAddition / LuaAdditionMethod (`a + b`) + - LuaSubtraction / LuaSubtractionMethod (`a - b`) + - LuaMultiplication / LuaMultiplicationMethod (`a * b`) + - LuaDivision / LuaDivisionMethod (`a /b `) + - LuaModulo / LuaModuloMethod (`a % b`) + - LuaPower / LuaPowerMethod (`a ^ b`) + - LuaFloorDivision / LuaFloorDivisionMethod (`a // b`, only when targeting Lua 5.3 or later) + - LuaNegation / LuaNegationMethod (`-x`) +- Bitwise operators (only when targeting Lua 5.3 or later) + - LuaBitwiseAnd / LuaBitwiseAndMethod (`a & b`) + - LuaBitwiseOr / LuaBitwiseOrMethod (`a | b`) + - LuaBitwiseExclusiveOr / LuaBitwiseExclusiveOrMethod (`a ^ b`) + - LuaBitwiseLeftShift / LuaBitwiseLeftShiftMethod (`a << b`) + - LuaBitwiseRightShift / LuaBitwiseRightShiftMethod (`a >> b`) + - LuaBitwiseNot / LuaBitwiseNotMethod (`~x`) +- LuaConcat / LuaConcatMethod (`a .. b`) +- LuaLength / LuaLengthMethod (`#x`) diff --git a/docs/advanced/writing-declarations.md b/docs/advanced/writing-declarations.md index 581118d4..360d1cd3 100644 --- a/docs/advanced/writing-declarations.md +++ b/docs/advanced/writing-declarations.md @@ -512,7 +512,9 @@ declare module "creator" { Lua supports overloading of mathematical operators such as `+`, `-` or `*`. This is performed using the [metatable methods](https://www.lua.org/manual/5.4/manual.html#2.4) `__add`, `__sub`, `__mul`, `__div`, and `__unm`. Since TypeScript does not support operator overloading in its type system, this feature is hard to replicate. Unfortunately, this is not something that can be fixed properly right now without forking off our custom TypeScript version. -However, there is a workaround that works decently: if you declare a type as an intersection type with `number`, it will inherit all mathematical operators. For example: +However, there are two possible workarounds. The first one is to declare a type as an intersection type with `number`. It will then inherit all mathematical operators. Keep in mind that this is only partially type safe and may require some additional casting. + +Example: ```ts declare type Vector = number & { @@ -530,6 +532,8 @@ const v3 = (v1 * 4) as Vector; const d = v3.dot(v2); ``` +The second option was added in version [0.38.0](https://github.com/TypeScriptToLua/TypeScriptToLua/blob/master/CHANGELOG.md#0380). You can now use [language extensions](https://typescripttolua.github.io/docs/advanced/language-extensions) that allow declaring special functions which will transpile to operators. This will be completely type safe if the operators are declared correctly. See [Operator Map Types](language-extensions.md#operator-map-types) for more information. + ### Import and export Using `import` can be important for making sure an _index.d.ts_ file contains all the declarations needed.