Ideas for a programming language similar to TypeScript that compiles to JavaScript. Somewhat of an inversion of DreamBerd.
// === and !== don't exist
"1" == 1 // TypeError
if (someString) {} // TypeError, must use someString != ""inspired by Rust
const x = 1 // ❌
let x = 1 // ✅
x++ // ❌
let mut y = 1
y++ // ✅
var z = 1 // ❌let myObj = { bar: 1 }
myObj.bar++ // ❌
let myObj2 = mut { bar: 1 }
myObj2.bar++ // ✅
myObj2 = {} // ❌ only properties are reassignable, since variable is not mutMaybe there are other cases in JS that need the no-gap rule in fun to get rid of semicolons
let x = 0; // ❌
let someValue = myArray
[0] // interpreted as an array literal, not an array accessor
someFunction
( // will be interpreted as an expression wrapper (e.g. IIFE)
someArgument
)let x = foo() // ❌
fn foo() => "hi"let myFunction = () =>
otherFunction(
evenAnotherFunction(
longComplicatedValue
)
) // ❌
fn myFunction() {
return otherFunction(
evenAnotherFunction(
longComplicatedValue
)
)
} // ✅inspired by Java and Effect
fn foo() => JSON.parse(someString)
// ^ () => unknown, throws JsonParseErrorfn parseUserJson(someString: string) {
return JSON.parse(someString)
.catch(JsonParseError, new UserJsonParseError)
// ^ UserJsonParseError has never been created before (one-off),
// must not collide with any other symbol
}
// ^ (someString: string) => unknown, throws UserJsonParseErrorfn foo() {
let fileData = readFileSync(...)
let networkResponse = fetchSomethingSync(...)
}
// ^ foo() => void, throws FSReadError, FetchNetworkError
fn bar() {
let _, error = foo()
catch (error, FSReadError) {
console.log(error.details)
}
}
// ^ bar() => void, throws FetchNetworkErrorfn strHasLength16orMore(str: string) => str.length >= 16
fn strHasNumbers(str: string) => str.match(/\d/) !== null
interface SignupDTO {
password: string([strHasLength16orMore, strHasNumbers]) // list of validators
}
fn signup(requestBodyJson: unknown) {
let { password } = SignupDTO.parse(requestBodyJson)
// ^ string
}
// ^ signup(requestBodyJson: unknown) => void, throws SchemaErrordocument.createElement() // ❌
navigation.back() // ❌
window.document.createElement() // ✅ (this will get me cancelled)inspired by Java method references
foo.filter(x => x.bar)
foo.filter(x => x.quux())
// equivalent
foo.filter(::bar)
foo.filter(::quux())let foo = cond1 ? (cond2 ? "a" : "b") : "c" // ❌fn foo(width: number, height: number) => ...
foo(8, 2) // ❌
foo(height: 2, width: 8) // ✅inspired by Python
from "package" import Foo, Bar as MyRenamedBar // default exports dont existimport "foo" // exports function "bar"
foo.bar()
import "package" as MyRenamedPackage
MyRenamedPackage.Fooimport effect "someFile.css" // discouraged, should be solved with a custom loader to create a `<link>` element for frontend stuffThis might be impossible to implement because something as innocent as a network request to get some data changes a lot in the overall system. The idea is more targeted towards having no practical consequences for the program state, like modifying variables.
let myModule = {
noSideEffect: () => "hi",
fn sideEffect() {
console#log("bye")
}
}
myModule.noSideEffect()
myModule#sideEffect()- remove
continue? - remove labelled statements? (for etc)
- replace
switchwithmatch(if keepingswitch, enforcebreakand remove it as keyword forswitch) - make
if-elsesyntactic sugar for ternary and removea ? b : ckeywords? - scoped exports: exported symbols should not be globally importable by default. e.g. by default they're only importable by files in the same folder, with different, looser or global scopes requiring explicit annotation. language servers (auto-complete) should naturally respect these restrictions. scoping should also be configurable for dependencies (e.g. banning the import of a library in some files/folders) but this might be more of a concern for linters, like can be done today using eslint with JS/TS.
- re-throwing errors should have a proper, type-safe way to include the previously catched error so it can be properly carried upwards and handled and inspected there if needed