Skip to content

Commit 475a612

Browse files
authored
added operator map types to language extensions (#24)
* added operator map types to language extensions * fixed link * ran prettier * updates from feedback Co-authored-by: Tom <tomblind@users.noreply.github.com>
1 parent 134aa47 commit 475a612

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

docs/advanced/language-extensions.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,79 @@ function myFunc(self)
6060
end
6161
foo, four = myFunc(nil)
6262
```
63+
64+
## Operator Map Types
65+
66+
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.
67+
68+
A common example of an overloaded operator is addition of a mathematical vector type:
69+
70+
```ts
71+
// Vector type supplied by a library, which supports math operators
72+
declare interface Vector {
73+
x: number;
74+
y: number;
75+
}
76+
77+
declare const a: Vector;
78+
declare const b: Vector;
79+
const result = a + b; // Not allowed in TS
80+
```
81+
82+
To support addition for this type, you can declare a special function:
83+
84+
```ts
85+
declare const addVector: LuaAddition<Vector, Vector, Vector>;
86+
const result = addVector(a, b); // transpiles to 'result = a + b'
87+
```
88+
89+
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`:
90+
91+
```ts
92+
declare namespace Vector {
93+
export const add: LuaAddition<Vector, Vector, Vector>;
94+
}
95+
96+
const result = Vector.add(a, b); // result = a + b
97+
```
98+
99+
There are also special variants for the mapping types that allow you do declare operator overloads as methods:
100+
101+
```ts
102+
declare interface Vector {
103+
add: LuaAdditionMethod<Vector, Vector>;
104+
}
105+
const result = a.add(b); // result = a + b
106+
```
107+
108+
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`:
109+
110+
```ts
111+
declare namespace Vector {
112+
export const mul: LuaMultiplication<Vector, Vector, number> & LuaMultiplication<Vector, number, Vector>;
113+
}
114+
115+
const dot: number = Vector.mul(a, b);
116+
const scaled: Vector = Vector.mul(a, 2);
117+
```
118+
119+
### Supported Operators:
120+
121+
- Math operators
122+
- LuaAddition / LuaAdditionMethod (`a + b`)
123+
- LuaSubtraction / LuaSubtractionMethod (`a - b`)
124+
- LuaMultiplication / LuaMultiplicationMethod (`a * b`)
125+
- LuaDivision / LuaDivisionMethod (`a /b `)
126+
- LuaModulo / LuaModuloMethod (`a % b`)
127+
- LuaPower / LuaPowerMethod (`a ^ b`)
128+
- LuaFloorDivision / LuaFloorDivisionMethod (`a // b`, only when targeting Lua 5.3 or later)
129+
- LuaNegation / LuaNegationMethod (`-x`)
130+
- Bitwise operators (only when targeting Lua 5.3 or later)
131+
- LuaBitwiseAnd / LuaBitwiseAndMethod (`a & b`)
132+
- LuaBitwiseOr / LuaBitwiseOrMethod (`a | b`)
133+
- LuaBitwiseExclusiveOr / LuaBitwiseExclusiveOrMethod (`a ^ b`)
134+
- LuaBitwiseLeftShift / LuaBitwiseLeftShiftMethod (`a << b`)
135+
- LuaBitwiseRightShift / LuaBitwiseRightShiftMethod (`a >> b`)
136+
- LuaBitwiseNot / LuaBitwiseNotMethod (`~x`)
137+
- LuaConcat / LuaConcatMethod (`a .. b`)
138+
- LuaLength / LuaLengthMethod (`#x`)

docs/advanced/writing-declarations.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,9 @@ declare module "creator" {
512512

513513
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.
514514

515-
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:
515+
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.
516+
517+
Example:
516518

517519
```ts
518520
declare type Vector = number & {
@@ -530,6 +532,8 @@ const v3 = (v1 * 4) as Vector;
530532
const d = v3.dot(v2);
531533
```
532534

535+
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.
536+
533537
### Import and export
534538

535539
Using `import` can be important for making sure an _index.d.ts_ file contains all the declarations needed.

0 commit comments

Comments
 (0)