tools/notes/CreateNewModule.md
There are several major scenarios when writing modules:
Example: matrix module
Declaration file (foo.d.ts):
export function a();
export class Foo {
public var1: number;
}
Implementation file (foo.ts):
import { Foo as FooDefinition } from ".";
export function a() {
// do something here
}
// require the definition and put implements clause to ensure API consistency between the declaration and implementation
export class Foo implements FooDefinition {
public var1: number;
}
Example: timer module
Declaration file (foo.d.ts):
export class Foo {
public running: number;
public start(): void;
public stop(): void;
}
Android implementation file (foo.android.ts):
import { Foo as FooDefinition } from ".";
// require the definition and put implements clause to ensure API consistency between the declaration and implementation
export class Foo implements FooDefinition {
public running: number;
public start(): void {
// Call android APIs - e.g. android.os.SystemClock.[xxx]
this.running = true;
}
public stop(): void {
// Call android APIs - e.g. android.os.SystemClock.[xxx]
this.running = false;
}
}
iOS implementation file (foo.ios.ts):
import { Foo as FooDefinition } from ".";
// require the definition and put implements clause to ensure API consistency between the declaration and implementation
export class Foo implements FooDefinition {
public running: number;
public start(): void {
// Call iOS APIs - e.g. Foundation.NSObject.[xxx]
this.running = true;
}
public stop(): void {
// Call iOS APIs - e.g. Foundation.NSObject.[xxx]
this.running = false;
}
}
In this case we will need to reuse the common JavaScript code and to split the implementation only for the platform specific native APIs. There are two different approaches here:
This is the way most of the UI modules are written.
Example: image module
Declaration file (foo.d.ts):
export class Foo {
public running: number;
public start(): void;
public stop(): void;
}
Common implementation file (foo-common.ts):
import { FooBase as FooDefinition } from ".";
// require the definition and put implements clause to ensure API consistency between the declaration and implementation
export class FooBase implements FooDefinition {
public running: number;
public start(): void {
this.running = true;
// add some common implementation here
}
public stop(): void {
this.running = false;
// add some common implementation here
}
}
Android implementation file (foo.android.ts):
import { FooBase } from "./foo-common";
// require the common file and extend the base common implementation
export class Foo extends FooBase {
public start(): void {
// call the base method which does the common job
super.start();
// add platform-specific implementation - e.g. call android.os.SystemClock.[xxx]
}
public stop(): void {
// call the base method which does the common job
super.stop();
// add platform-specific implementation - e.g. call android.os.SystemClock.[xxx]
}
}
iOS implementation file (foo.ios.ts):
import { FooBase } from "./foo-common";
// require the common file and extend the base common implementation
export class Foo extends FooBase {
public start(): void {
// call the base method which does the common job
super.start();
// add platform-specific implementation - e.g. call Foundation.NSObject.[xxx]
}
public stop(): void {
// call the base method which does the common job
super.stop();
// add platform-specific implementation - e.g. call Foundation.NSObject.[xxx]
}
}
Example: file-system module (Note: file-system-access is the platform specific implementation)
Declaration file (foo.d.ts):
export class Foo {
public running: number;
public start(): void;
public stop(): void;
}
Native Implementation Declaration file (foo-native.d.ts):
//@private
// The above statement marks this definition as private so that it is not visible to the users
export function startNative();
export function stopNative();
Android Native Implementation file (foo-native.android.ts):
export function startNative(){
// call native code here
}
export function stopNative(){
// call native code here
}
iOS Native Implementation file (foo-native.ios.ts):
export function startNative(){
// call native code here
}
export function stopNative(){
// call native code here
}
Common implementation file (foo.ts):
import { FooBase as FooDefinition } from ".";
import { startNative, stopNative } from "./foo-native";
// require the definition and put implements clause to ensure API consistency between the declaration and implementation
export class Foo implements FooDefinition {
public running: number;
public start(): void {
this.running = true;
// do the native call through the Facade
startNative();
}
public stop(): void {
this.running = false;
// do the native call through the Facade
stopNative();
}
}