println("Hello, world!")
console.log("Hello, world!");
var myVariable = 42
myVariable = 50
val myConstant = 42
let myVariable = 42;
myVariable = 50;
const myConstant = 42;
val explicitDouble: Double = 70.0
// Boolean
// Byte, Short, Int, Long, Float, Double, UByte, UShort, UInt, ULong
// String
// Any, Unit
// Nothing
// dynamic
external fun require(module:String): dynamic
const explicitDouble: number = 70;
// boolean
// number, bigint
// string
// any, void
// never
// undefined, unknown, null, Symbol, union: string|number, string|object
declare const welcome: any;
val label = "The width is "
val width = 94
val widthLabel = label + width
const label = "The width is ";
const width = 94;
const widthLabel = label + width;
typealias Name = String;
typealias NameResolver = () -> String;
type Name = string;
type NameResolver = () => string;
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
function foo2(arg: unknown) {
if (typeof arg === "string") {
// We know this is a string now.
console.log(arg.toUpperCase());
}
}
//Structural Equality (‘==’), Referential equality (‘===’), .equals method
data class User(val id: Int, val nick: String)
fun testEquals() {
val first: Any = User(1, "linux_china")
val second: Any = User(1, "linux_china")
println(first == second) //true
println(first === second) //false, Referential different
println(first.equals(second)) //true
}
//Equals Operator ( == ), Strict Equals Operator ( === )
let a: any = 10;
let b: any = "10"
console.log(a == b); //true
console.log(a == b); //true
console.log(a === b); //false, type different
val name1: String = "xx"
var name2: String? = null
fun testNullable() {
name2.length //illegal
name2?.length //nullable check
name2!!.length //you know that
}
// Elvis Operator
val name3 = name2 ?: "good";
let name1: string = "xx"
let name2: string | null = null
name2.length //null check validation
let len = name2?.length //nullable check
name2!.length //you know that
//Nullish Coalescing
let x1 = name2 ?? "default value";
val apples = 3
val oranges = 5
val fruitSummary1 = "I have ${apples + oranges} pieces of fruit."
val fruitSummary2 = """I have ${apples + oranges} pieces of fruit."""
val fruitSummary3 = html("""I have ${apples + oranges} pieces of fruit.""")
const apples = 3;
const oranges = 5;
const fruitSummary1 = `I have ${apples + oranges} pieces of fruit.`;
const fruitSummary2 = html`I have ${apples + oranges} pieces of fruit.`;
val names = arrayOf("Anna", "Alex", "Brian", "Jack")
val count = names.count()
for (i in 0..count - 1) {
println("Person ${i + 1} is called ${names[i]}")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
import * as _ from 'lodash';
const names = ["Anna", "Alex", "Brian", "Jack"];
const count = names.length;
for (let i of _.range(0, count)) {
console.log(`Person ${i + 1} is called ${names[i]}`)
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
for (index in 1..5) {
println("$index times 5 is ${index * 5}")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
import * as _ from 'lodash';
for(let index of _.range(1, 6)) {
console.log(`${index} times 5 is ${index * 5}`)
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
fun main12() {
val shoppingList = arrayOf(
"catfish", "water",
"tulips", "blue paint"
)
shoppingList[1] = "bottle of water"
val freezeList = listOf("first", "second", "third")
val mutableList = mutableListOf("first", "second", "third")
}
let shoppingList = ["catfish", "water",
"tulips", "blue paint"];
shoppingList[1] = "bottle of water";
val set1 = setOf(1 , 2 , 3 , 4 , 3)
val mutableSet = mutableSetOf(1 , 2 , 3 , 4 , 3);
let mySet = new Set(); //ES2015
mySet.add(1);
mySet.delete(1)
val wordsSequence = listOf("one", "two", "three", "four").asSequence()
val list2 = wordsSequence
.filter { println("filter: $it"); it.length > 3 }
.map { println("length: ${it.length}"); it.length }
.toList()
let words = ["catfish", "water", "tulips", "blue paint"];
let list2 = words.filter(word => {
return word.length > 3;
}).map(word => {
return word.length
});
val occupations = mutableMapOf(
"Malcolm" to "Captain",
"Kaylee" to "Mechanic"
)
occupations["Jayne"] = "Public Relations"
let occupations = {
"Malcolm": "Captain",
"Kaylee": "Mechanic",
};
occupations["Jayne"] = "Public Relations";
// data class as Tuple in Kotlin
data class GasPrices(val a: Double, val b: Double, val c: Double)
fun main7() {
val price = GasPrices(3.59, 3.69, 3.79)
val (a, b, _) = price
}
type GasPrices = [number, number, number]
//Labeled Tuple
type Range = [start: number, end: number];
function main4() {
let price: GasPrices = [3.59, 3.69, 3.79]
let [a, b, c] = price;
}
fun main13() {
val shoppingList = arrayOf("catfish", "water", "tulips", "blue paint")
shoppingList.filter { it.startsWith("c") }
.map { it.length }
.reduce { acc, i -> acc + i }
shoppingList.filter { it.startsWith("c") }
.forEach(::println)
}
let shoppingList2 = ["catfish", "water", "tulips", "blue paint"];
shoppingList2
.filter(item => item.startsWith("c"))
.map(item => item.length)
.reduce((acc, item) => acc + item)
shoppingList2
.filter(item => item.startsWith("c"))
.forEach(item => {
console.log(item)
})
val emptyArray = arrayOf<String>()
val emptyMap = mapOf<String, Float>()
const emptyArray: string[];
const emptyDictionary: {[key: string]: number};
fun greet(name: String, day: String): String {
return "Hello $name, today is $day."
}
greet("Bob", "Tuesday")
function greet(name: string, day: string): string {
return `Hello ${name}, today is ${day}.`
}
greet("Bob", "Tuesday");
fun sumOf(vararg numbers: Int): Int {
var sum = 0
for (number in numbers) {
sum += number
}
return sum
}
fun main3() {
sumOf(42, 597, 12)
// sumOf() can also be written in a shorter way:
fun sumOf(vararg numbers: Int) = numbers.sum()
}
function sumOf(...numbers: number[]): number{
let sum = 0;
for (let number of numbers) {
sum += number;
}
return sum;
}
sumOf(42, 597, 12);
fun makeIncrementer(): (Int) -> Int {
val addOne = fun(number: Int): Int {
return 1 + number
}
return addOne
}
val increment = makeIncrementer()
increment(7)
// makeIncrementer can also be written in a shorter way:
fun makeIncrementer() = fun(number: Int) = 1 + number
function makeIncrementer():(number) => number{
function addOne(number: number): number {
return 1 + number;
}
return addOne
}
let increment = makeIncrementer();
increment(7);
// makeIncrementer can also be written in a shorter way:
let makeIncrementer = () => (number: number) => 1 + number;
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (source: string, subString: string) {
let result = source.search(subString);
return result > -1;
};
//lambda
val printText = { text: String ->
println(text)
}
//arrow function
let printText = (text: string) => {
console.log(text)
}
fun area(width: Int, height: Int) = width * height
area(width = 2, height = 3)
// This is also possible with named arguments
area(2, height = 2)
area(height = 3, width = 2)
function area({width, height}:{width:number, height:number}):number {
return width * height;
}
area({width: 2, height: 3});
fun identity(value: T): T {
return value
}
val str = identity("Hello")
function identity(value: T): T {
return value;
}
let str: string = identity("Hello");
val sequence2 = sequence {
val start = 0
// yielding a single value
yield(start)
// yielding an iterable
yieldAll(1..5 step 2)
// yielding an infinite sequence
yieldAll(generateSequence(8) { it * 3 })
}
println(sequence2.take(7).toList()) // [0, 1, 3, 5, 8, 24, 72]
function* counter(max: number): Generator {
let i = 0;
while (i < max) {
if (yield i++) {
break;
}
}
}
for (let num of counter(3)) {
console.log(num);
}
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
fun simple(): Flow = flow { // flow builder
for (i in 1..3) {
delay(100) // pretend we are doing something useful here
emit(i) // emit next value
}
}
fun main() = runBlocking {
// Collect the flow
simple().collect { value -> println(value) }
}
// async generator function
async function* g() {
yield 1;
await sleep(100);
yield* [2, 3];
yield* (async function*() {
await sleep(100);
yield 4;
})();
}
async function f() {
//The for-await-of Statement
for await (const x of g()) {
console.log(x);
}
}
//Optional Parameters by default value
fun sayHello(name: String = "") {
}
fun main4() {
sayHello()
sayHello("Jackie")
}
// Optional Parameters
function sayHello(hello?: string) {
console.log(hello);
}
//default-initialized parameters
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
sayHello()
sayHello("Jackie")
buildName("Jack")
buildName("Jack", "Ma")
import kotlin.js.RegExp
fun String.isEmailValid(): Boolean {
val pattern = RegExp("^[\\w.-]+@([\\w\\-]+\\.)+[A-Z]{2,8}$", "i")
return pattern.test(this)
}
declare interface String {
isEmailValid(): boolean;
}
String.prototype.isEmailValid = function (this: string): boolean {
let re = new RegExp("^[\\w.-]+@([\\w\\-]+\\.)+[A-Z]{2,8}$", 'i');
return re.test(this);
};
class Shape {
private var numberOfSides = 0
constructor(numberOfSides: Int) {
this.numberOfSides = numberOfSides
}
fun simpleDescription() =
"A shape with $numberOfSides sides."
}
val shape2 = Shape(4)
class Shape {
numberOfSides = 0;
constructor(numberOfSides: number) {
this.numberOfSides = numberOfSides;
}
simpleDescription(){
return `A shape with ${this.numberOfSides} sides.`;
}
}
let shape2 = new Shape(4)
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
let shape = new Shape();
shape.numberOfSides = 7;
let shapeDescription = shape.simpleDescription();
open class NamedShape(val name: String) {
var numberOfSides = 0
open fun simpleDescription() =
"A shape with $numberOfSides sides."
}
class Square(var sideLength: BigDecimal, name: String) :
NamedShape(name) {
init {
numberOfSides = 4
}
fun area() = sideLength.pow(2)
override fun simpleDescription() =
"A square with sides of length $sideLength."
}
val test = Square(BigDecimal("5.2"), "square")
test.area()
test.simpleDescription()
class NamedShape {
numberOfSides: number = 0;
name: string;
constructor(name: string) {
this.name = name
}
simpleDescription():string {
return `A shape with ${this.numberOfSides} sides.`;
}
}
class Square extends NamedShape {
sideLength: number;
constructor(sideLength: number, name: string) {
super(name);
this.sideLength = sideLength;
this.numberOfSides = 4;
}
area(): number {
return this.sideLength * this.sideLength;
}
simpleDescription(): string {
return "A square with sides of length " +
this.sideLength + ".";
}
}
let test = new Square(5.2, "square");
test.area();
test.simpleDescription();
var movieCount = 0
var songCount = 0
class Movie
class Song
fun main10() {
val library: List = listOf("first")
for (item in library) {
if (item is Movie) {
++movieCount
} else if (item is Song) {
++songCount
}
}
}
let movieCount = 0;
let songCount = 0;
class Movie {
}
class Song {
}
let library: unknown[] = [new Movie(), new Song()]
for (const item of library) {
if (item instanceof Movie) {
++movieCount;
} else if (item instanceof Song) {
++songCount;
}
}
for (current in someObjects) {
if (current is Movie) {
println("Movie: '${current.name}', " +
"dir. ${current.director}")
}
}
for (let current in someObjects) {
if (current instanceof Movie) {
console.log(`Movie: '${movie.name}', ` +
`dir. ${movie.director}`);
}
}
interface Nameable {
fun name(): String
}
fun f<T: Nameable>(x: T) {
println("Name is " + x.name())
}
interface Nameable {
name(): string;
}
function f(x: Nameable) {
console.log("Name is " + x.name());
}
//mixin in Kotlin just Kotlin interface
interface MyInterface {
val prop: Int // abstract
fun foo() {
print(prop)
}
}
class Child : MyInterface {
override val prop: Int = 29
}
// Disposable Mixin
class Disposable {
isDisposed: boolean = false;
dispose() {
this.isDisposed = true;
}
}
class SmartObject {
}
interface SmartObject extends Disposable {
}
applyMixins(SmartObject, [Disposable]);
let smartObj = new SmartObject();
smartObj.dispose();
function applyMixins(derivedCtor: any, baseCtors: any[]) {
baseCtors.forEach(baseCtor => {
Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
// @ts-ignore
Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name));
});
});
}
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
enum Direction {
NORTH, SOUTH, WEST, EAST
}
enum Arrow {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy
@Fancy class Foo {
@Fancy fun baz(@Fancy foo: Int): Int {
return (@Fancy 1)
}
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
val helloWorld = object {
val hello = "Hello"
val world = "World"
// object expressions extend Any, so `override` is required on `toString()`
override fun toString() = "$hello $world"
}
const helloWorld = {
name: (): string => {
return "";
}
}
class Config {
operator fun invoke(): String {
return "invoke"
}
}
fun main5() {
val config = Config()
println(config())
}
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = (function (start: number) {
console.log("start")
}) as Counter;
counter.interval = 123;
counter.reset = function () {
};
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
//Indexed access operator
class StringArray {
operator fun get(index: Int): String {
return ""
}
operator fun set(index: Int, value: String) {
}
operator fun get(index: String): String {
return ""
}
operator fun set(index: String, value: String) {
}
}
fun main8() {
val stringArray = StringArray()
stringArray[0]
stringArray["first"] = "second"
}
//Indexed access operator
class StringArray {
operator fun get(index: Int): String {
return ""
}
operator fun set(index: Int, value: String) {
}
operator fun get(index: String): String {
return ""
}
operator fun set(index: String, value: String) {
}
}
fun main8() {
val stringArray = StringArray()
stringArray[0]
stringArray["first"] = "second"
}
data class Point(val x: Double, val y: Double)
val point = Point(1.0, 2.0);
type Point = {
x: number,
y: number
}
let point: Point = {x: 1.0, y: 2.0};
//use val for readonly
data class Foo2(val bar: Double, val bas: Double)
fun main11() {
val foo2 = Foo2(1.0, 2.0)
foo2.bar = 2.0 //illegal
}
type Foo2 = {
readonly bar: number;
readonly bas: number;
};
const foo: Foo2 = {bar: 123, bas: 456};
foo.bar = 456; // illegal
class Box(val value: T) {
}
val box = Box(1.0)
class Box {
value: T;
constructor(value: T) {
this.value = value;
}
}
let x: Box = new Box(1.0);
class MyClass {
private val store = mutableMapOf()
operator fun get(key: String): Any? {
return store[key]
}
operator fun set(key: String, value: Any) {
store[key] = value
}
}
interface DictionarySupport {
[index: string]: any;
}
suspend fun findNickById(id: Int): String {
return "nick $id"
}
suspend fun main() {
val nick = findNickById(1)
}
//Promise
const promise1 = new Promise((resolve, reject) => {
resolve("good")
//reject(new Error('failed'));
});
promise1.then(value => {
console.log('Hi', value);
}).catch(error => {
console.log('Oops', error);
});
(async () => {
let value = await promise1
console.log(value)
})();
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.onEach
fun findVip(): Flow {
return arrayOf("first", "second").asFlow()
}
fun main2() {
findVip().onEach {
print(it)
}
}
import { from } from 'rxjs';
const result = from( [10, 20, 30]);
result.subscribe(x => console.log(x));
package validation
import kotlin.js.RegExp
val zipCodeRegex = RegExp("[0-9]+")
interface StringValidator {
fun isAcceptable(s: String): Boolean;
}
class ZipCodeValidator : StringValidator {
override fun isAcceptable(s: String): Boolean {
return s.length == 5 && zipCodeRegex.test(s);
}
}
namespace Validation {
const numberRegexp = /^[0-9]+$/;
export interface StringValidator {
isAcceptable(s: string): boolean;
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string): boolean {
return s.length === 5 && numberRegexp.test(s);
}
}
}
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZipCode"] = new Validation.ZipCodeValidator();
@file:JsModule("lodash")
package lodash
@JsName("toUpper")
external fun toUpper(text: String): String
//index.d.ts
export = _;
export as namespace _;
declare const _: _.LoDashStatic;
declare namespace _ {
interface LoDashStatic {
}
}
@JsExport
@JsName("hello")
fun hello(name: String): String {
return "Hello name"
}
export function hello(name: string): string {
return `Hello ${name}!`
}
// testImplementation(kotlin("test-js")) in build.gradle.ts
import kotlin.test.Test
import kotlin.test.assertEquals
class DemoTest {
@Test
fun testBar() {
console.log("Hello World!")
assertEquals(4, 2 * 2)
}
}
// jest, ts-jest
test("hello test", () => {
console.log("hello test");
});
### Kotlin Tools
* Gradle: project build tool with dev server support
* dukat: Convert declarations(d.ts) to Kotlin external declarations
### TypeScript Tools
* npm/yarn: project build tool
* webpack: bundle your assets and dev-server support
//When expression
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
// DSL
html {
head {
title {+"XML encoding with Kotlin"}
}
}
//Operator overloading: https://kotlinlang.org/docs/operator-overloading.html#unary-operations
//Delegated properties
class Example {
var p: String by Delegate()
}
// tagged literal
const code = html`xxx`
//String Literal Types
type EventType = "click" | "mouseover";
// union
type TextOrNumber = string | number;
// tuple
let x2: [string, number] = ["hello", 10];