How to alias complex type constructor in typescript? - oop

I am using a custom library, and for some types I have to write:
import * as pipeline from 'custom-pipeline';
import {MapTransform} from 'custom-pipeline';
export const createTransform = (appConfig: IAppConfig):
MapTransform<ISomeData, IFoo> |
MapTransform<ISomeData, IBar> => {
switch(appConfig.createType) {
case 'foo':
return new pipeline.MapTransform<ISomeData, IFoo>((data: ISomeData) => {...});
case 'bar':
return new pipeline.MapTransform<ISomeData, IBar>((data: ISomeData) => {...});
}
}
Especially the verbose constructor is irking me. I can I alias the types alright:
type FooTransform = MapTransform<ISomeData, IFoo>;
type BarTransform = MapTransform<ISomeData, IBar>;
Yet I cannot do:
new FooTransform((data: ISomeData) => {...});
new BarTransform((data: ISomeData) => {...});
throwing an error like:
error TS2304: Cannot find name 'FooTransform'.
I assume it's because I only have a type and not a class? Yet how can I alias the constructor in a way that I can do new FooTransform as above?
The definition of MapTransform looks like:
export declare class MapTransform<A, B> extends BaseTransform<A, B> {
constructor(private mapFunc: (val: A) => B);
}
I can reduce the constructor to this:
fooMapFunction = (data: ISomeData): IFoo => {...};
new MapTransform<ISomeData, IFoo>(mapFunction);
Albeit it's not en par with a new FooTransform(fooMapFunction).

Your assumption is correct, type declarations are compile-time only, thus you can't perform any operations on them (including instantiation with new).
Solution 1: Type Assertion
Let's assume the superclass looks like this:
class MapTransform<T1> {
constructor(public readonly data: T1) { /* ... */ }
}
To create a specialised type alias, you can do this:
type TransformA = MapTransform<number>;
From the perspective of the superclass MapTransform, there's no difference between MapTransform<A>, MapTransform<B> and so on (that's the point of generics), so we can safely assign the constructor function of class MapTransform to a constant TransformA. Calling new TransformA() is, at runtime, identical to calling new MapTransform<number>():
const TransformA = <{ new (data: number): TransformA; }>MapTransform;
Notice the type assertion? This tells the TypeScript compiler to treat the assigned value MapTransform as an object which constructs an object of type TransformA when instantiating it with new. We can now write:
const a = new TransformA(123);
a.data.toExponential(); // works
BTW, what the TypeScript compiler actually sees is this ...
const TransformA = <{ new (data: number): MapTransform<number>; }>MapTransform;
... because type TransformA ≡ MapTransform<number>.
Be aware that all of these will evaluate true:
new TransformA(123) instanceof TransformA
new TransformA(123) instanceof MapTransform
new MapTransform<number>(123) instanceof TransformA
new MapTransform<number>(123) instanceof MapTransform
Here's the example in the TypeScript Playground.
Solution 2: Subclassing
Again, let's assume the superclass looks like this:
class MapTransform<T1> {
constructor(public readonly data: T1) { /* ... */ }
}
With subclassing, the solution is simple: Extend the superclass and pass the desired type parameters along in the extends clause.
class TransformA extends MapTransform<number> { }
Et voilà, you now have a constructor that works at runtime as well as a type that works at compile-time.
Unlike the first solution, the following 2 expressions will evaluate true ...
new TransformA(123) instanceof TransformA
new TransformA(123) instanceof MapTransform
... while these will evaluate false:
new MapTransform<number>(123) instanceof TransformA
new MapTransform<number>(123) instanceof MapTransform
Solution 2.1: Anonymous Subclassing
If you only need the constructor alias but not the type alias, this might come in handy:
const TransformA = class extends MapTransform<number> { };
This is called a class expression and can be used like every other expression, for example:
class App {
private static TransformA = class extends MapTransform<number> { };
public doStuff() {
return new App.TransformA(123);
}
}
More on Types
If you're interested, here's a few more links on the topic:
Named Types in TypeScript Spec
Type Assertions
TypeScript Handbook: Interfaces, specifically section "Difference between the static and instance sides of classes"
Class Expressions
EDIT
You wrote you've had issues applying these solutions to a class that expects a function as a parameter, so here's another example in the TypeScript playground.

Related

OOP - How to create an instance of one type called to another type in Reason

I have two abstract products types:
type abstractProductA = {.
methodA: string
};
type abstractProductB = {.
methodB: int
};
Used to create the following product classes:
class productA1 = {
pub methodA => "This is methodA of ProductA1";
};
class productB1 = {
pub methodB => 1;
};
I would like to call the instance of abstractProductA, as well as abstractProductB in my abstract factory. Something like the following(syntax is off, I know):
type abstractFactory = {.
createProductA: abstractProductA,
createProductB: abstractProductB
};
So that when I create new concreteFactory using the following class:
class concreteFactory1 = {
pub createProductA => (new productA1);
pub createProductB => (new productA1);
};
and constructer:
let g = new concreteFactory1#createProductB;
Js.log (g#methodA);
the compiler should complain that createProductB only takes an int, and not an string(which it currently does not).
Thank you, and any suggestions are more than welcome.
It seems the error should occur where createProductB returns productA1 instead of productB1. In order to achieve that, you'll need to define a virtual class for abstractFactory instead of just an object type, and then have concreteFactory explicitly inherit from it.
class virtual abstractFactory = {
pub virtual createProductA: abstractProductA;
pub virtual createProductB: abstractProductB;
};
class concreteFactory1 = {
inherit abstractFactory;
pub createProductA => (new productB1);
pub createProductB => (new productB1);
};
This will produce the following error on pub createProductA => (new productB1):
This expression has type productB1 but an expression was expected of type abstractProductA The second object type has no method methodB
See the full example here

Passing parameters to a custom getter in kotlin

I have been reading about properties in Kotlin, including custom getters and setters.
However, I was wondering if it is possible to create a custom getter with extra parameters.
For example, consider the following method in Java:
public String getDisplayedValue(Context context) {
if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
Note that the static method in PrefUtils has to have Context as a parameter, so removing this is not an option.
I would like to write it like this in Kotlin:
val displayedValue: String
get(context: Context) {
return if (PrefUtils.useImperialUnits(context)) {
// stuff
} else {
// other stuff
}
}
But my IDE highlights all of this in red.
I am aware I can create a function in my class to get the displayed value, but this would mean I would have to use .getDisplayedValue(Context) in Kotlin as well instead of being able to refer to the property by name as in .displayedValue.
Is there a way to create a custom getter like this?
EDIT: If not, would it be best to write a function for this, or to pass Context into the parameters of the class constructor?
As far as I know, property getter cannot have parameter. Write a function instead.
You can do this by having a property that returns an intermediate object that has a get and/or set operator with the parameters that you want, rather than returning the value directly.
Having that intermediate object be an inner class instance may be useful for providing easy access to the parent object. However, in an interface you can't use inner classes so in that case you might need to provide an explicit constructor parameter referencing the parent object when constructing your intermediate object.
For instance:
class MyClass {
inner class Foo {
operator fun get(context: Context): String {
return if (PrefUtils.useImperialUnits(context)) {
// return stuff
} else {
// return other stuff
}
}
}
val displayedValue = Foo()
}
...
val context : Context = whatever
val mc : MyClass = whatever
val y: String = mc.displayedValue[context]
You can do for example:
val displayedValue: String by lazy {
val newString = context.getString(R.string.someString)
newString
}

Access the getter and setter of a typescript property

I have a question about typescript properties: Is it possible to get the setter and getter of a typescript property or to declare a function argument to be of a property of X type?
The reason is to get some sort of "reference" to a variable which is not possible in plain JS without writing getter/setter wrappers or access the variable via parent object itself (obj["varname"]).
For example (with some working code and other parts speculative):
//A sample class with a property
class DataClass<T> {
private T val;
public get value(): T {
return this.val;
}
public set value(value: T) {
this.val = value;
}
}
//Different ways of modifing a member "by reference"
class ModifyRef {
public static void DoSomethingByGetterAndSetter(getter: () => string, setter: (val: string) => void) {
var oldValue = getter();
setter("new value by DoSomethingByGetterAndSetter");
}
public static void DoSomethingByObject(obj: Object, name: string) {
var oldValue = obj[name];
obj[name] = "new value by DoSomethingByObject";
}
//Is something like this possible?
public static void DoSomethingByProperty(somePropery: property<string>) {
var oldVlaue = someProperty;
someProperty = "new value by DoSomethingByProperty";
}
}
var inst = new DataClass<string>();
//Calling the DoSomethingByProperty if possible
ModifyRef.DoSomethingByProperty(inst.value);
//Or if not is something like this possible
ModifyRef.DoSomethingByGetterAndSetter(inst.value.get, inst.value.set);
The simplest way to do this would be to provide methods, rather than a property:
//A sample class with a property
class DataClass<T> {
private val: T;
public getValue(): T {
return this.val;
}
public setValue(value: T) {
this.val = value;
}
}
class ModifyRef {
public static DoSomethingByGetterAndSetter(getter: () => string, setter: (val: string) => void) {
var oldValue = getter();
setter("new value by DoSomethingByGetterAndSetter");
}
}
var inst = new DataClass<string>();
//Or if not is something like this possible
ModifyRef.DoSomethingByGetterAndSetter(inst.getValue, inst.setValue);
I've long found it very surprising that languages with properties don't include a convenient way to make a reference to a property, and have daydreamed about having this feature in C#. It ought to work on local variables as well.
A popular pattern for this kind of first-class or reified property is a single function that can be called in two ways:
no arguments: returns current value.
one argument: sets value, returns undefined.
Or in TypeScript terms:
interface Property<T> {
(): T;
(newVal: T): void;
}
The methods of jQuery objects often work like this. An example of this pattern in modelling pure data is in Knockout, in which such properties also support change subscriptions, and there's a rather elegant pattern for defining computed properties that automatically recompute when their dependencies change.

TypeScript Interface signature for property without setter.

We have a typical getter in one of our classes, lets say
class Employee implements IEmployee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
}
and an interface to work with it
interface IEmployee{
fullName: string;
}
When working with an instance via this interface the compiler will not warn us about absence of a setter if we try to assign to fullName, and the the JS runtime simply swallows any assignment and does not throw an error. Is there any way to mark interface member as having only getter or only setter?
I've seen this post, but it is quite old, i want to know, if anything improved.
Properties in typescript can now have 'readonly' modifier, which achieves the desired restult.
interface IEmployee{
readonly fullName: string;
}
This is an interesting question. The concept of a readonly property is subtly different in TypeScript to other languages.
In many languages a property with a getter (but no setter) would raise a compiler error if you attempted to set the property, but TypeScript doesn't.
The property is still readonly, because it makes no difference if you attempt to set it; the set will fail silently.
Here is an example without any interfaces:
class Example {
get name() {
return 'Steve';
}
}
var y = new Example();
y.name = 'Example 2';
alert(y.name);
There is no compiler warning when I use x.name = 'Example 2';.
If there was a compiler warning, I would subsequently expect there to be a way of specifying the readonly-ness of a property within an interface. As you'd expect though, given the above information, you can't set a readonly property on an interface.
interface Test {
name: string;
}
class Example {
get name() {
return 'Steve';
}
}
var x: Test = new Example();
x.name = 'Example 1';
alert(x.name);
var y = new Example();
x.name = 'Example 2';
alert(x.name);
This means you can only enforce readonly-ness by having a method to get the value of the property (and obviously no method that allows it to be set).
interface Test {
getName: () => string;
}
class Example {
getName() {
return 'Steve';
}
}
var x: Test = new Example();
//x.getName('Obviously not');
//x.getName() = 'Obviously not';
alert(x.getName());
var y = new Example();
//y.getName('Obviously not');
//y.getName() = 'Obviously not';
alert(y.getName());

typescript interface initialization

My level of typescript is 'ABSOLUTE BEGINNER' but I have a good OOP background. I am building an with typescript that reference an external t.ds library that contains the following interface:
interface ISimpleObject {
foo: string;
bar?: any;
}
Now, if I want to call a method that has an IRequestConfig parameter, how do I create one? I can see different options:
Create a simple implementation of ISimpleObject. I don't like this approach because it looks like boilerplate code to me
don't initialize the object (I fear this could break something...):
var x :IsimpleObject;
x.bar = 'xxx';
callMethod(x);
Cast a pojo:
var x :IsimpleObject = <IsimpleObject>{foo: 'yyy', bar:'xxx'};
I don't like this approach either because it doesn't enforce type safety...
I guess this is a fairly trivial question and I am missing something trivial about typescript.
Typescript2:
const simpleObject = {} as ISimpleObject;
If you have an interface like:
interface ISimpleObject {
foo: string;
bar?: any;
}
This interface is only used at compile time and for code-hinting/intellisense. Interfaces are used to provide a rigorous and type-safe way of using an object with a defined signature in a consistent manner.
If you have a function using the interface defined above:
function start(config: ISimpleObject):void {
}
The TypeScript compile will fail if an object does not have the exact signature of the ISimpleObject interface.
There are multiple valid techniques for calling the function start:
// matches the interface as there is a foo property
start({foo: 'hello'});
// Type assertion -- intellisense will "know" that this is an ISimpleObject
// but it's not necessary as shown above to assert the type
var x = <ISimpleObject> { foo: 'hello' };
start(x);
// the type was inferred by declaration of variable type
var x : ISimpleObject = { foo: 'hello' };
start(x);
// the signature matches ... intellisense won't treat the variable x
// as anything but an object with a property of foo.
var x = { foo: 'hello' };
start(x);
// and a class option:
class Simple implements ISimpleObject {
constructor (public foo: string, public bar?: any) {
// automatically creates properties for foo and bar
}
}
start(new Simple("hello"));
Any time the signature doesn't match, the compile will fail:
// compile fail
var bad = { foobar: 'bad' };
start( bad );
// compile fail
var bad: ISimpleObject = { foobar: 'bad' };
// and so on.
There is no "right" way to do it. It's a matter of style choice. If it were an object that was constructed (rather than just directly passed as a parameter), I'd normally declare the type:
var config: ISimpleObject = { foo: 'hello' };
That way code-completion/IntelliSense will work anywhere I used the config variable:
config.bar = { extra: '2014' };
There is no "casting" in TypeScript. It is called a type assertion and shouldn't be needed in the cases described here (I included an example above where it could be used). There's no need to declare the variable Type and then use an assertion in this case (as the type was already known).
You can't create an instance of an interface since Typescript doesn't "translate" it into js. You can check the js that is created and you will see nothing in it. It's simple for compile errors, type safety and intelisense.
interface IStackOverFlow
{
prop1 : string;
prop2 : number;
}
public MyFunc(obj : IStackOverFlow)
{
// do stuff
}
var obj = {prop1: 'str', prop2: 3};
MyFunc(obj); // ok
var obj2 = {prop1: 'str'};
MyFunc(obj); // error, you are missing prop2
// getObj returns a "any" type but you can cast it to IStackOverFlow.
// This is just an example.
var obj = <IStackOverFlow> getObj();