Iterating over module exports with implicit any - angularjs

So I'm writing a module with sub-modules for angular. Notation:
module App.services {
export class SomeService { }
}
and I initialize all services using:
function defToArray(def: any): any[] {
return (def.dependencies || []).concat(def)
}
for (var s in App.services)
app.service(s, defToArray(App.services[s]));
However defToArray(App.services[s]) causes "Index signature of object type implicitly has an 'any' type".
I already tried casting like defToArray(<any>App.services[s]) and defToArray(App.services[s] as any), but no luck.
Any thoughts?

Casts are not very tightly binding.
Instead of
defToArray(<any>App.services[s])
try
defToArray((<any>App.services)[s])
or if you prefer
defToArray((<{[key:string]:any}>App.services)[s])
For clarification, the goal here is not to cast the type of App.services[s], you're actually trying to provide type information for the access-by-index operator. This is only an issue when noImplicitAny is enabled (but IMO it always should be, so it's just one of the things you learn to adjust to)

Related

TypeScript Discriminated Union with Optional Discriminant

I've created a discriminated union that's later used to type props coming into a React component. A pared down sample case of what I've created looks like this:
type Client = {
kind?: 'client',
fn: (updatedIds: string[]) => void
};
type Server = {
kind: 'server',
fn: (selectionListId: string) => void
};
type Thing = Client | Server;
Note that the discriminant, kind, is optional in one code path, but is defaulted when it is destructured in the component definition:
function MyComponent(props: Thing) {
const {
kind = 'client',
fn
} = props;
if (kind === 'client') {
props.fn(['hey']);
// also an error:
// fn(['hey'])
} else {
props.fn('hi')
// also an error:
// fn('hey')
}
}
What I'm trying to understand is what's going on with this conditional. I understand that the type checker is having trouble properly narrowing the type of Thing, since the default value is separate from the type definition. The oddest part is that in both branches of the conditional it insists that fn is of type (arg0: string[] & string) => void and I don't understand why the type checker is trying to intersect the parameters here.
I would have expected it to be unhappy about non-exhaustiveness of the branches (i.e. not checking the undefined branch) or just an error on the else branch where the 'server' and undefined branches don't line up. But even trying to rearrange the code to be more explicit about each branch doesn't seem to make any impact.
Perhaps because the compiler simply can't narrow the types so tries an intersection so it doesn't matter which path--if the signatures are compatible then it's fine to call the function, otherwise you basically end up with a never (since string[] & string is an impossible type)?
I understand that there are a variety of ways I can resolve this via user-defined type predicates or type assertions, but I'm trying to get a better grasp on what's going on here internally and to find something a bit more elegant.
TS Playground link
It's an implementation detail in TS. Types are not narrowed when you are storing the value in a different variable. The same issue exists for the square bracket notation. You can refer to this question, it deals with a similar issue. Apparently, this is done for compiler performance.
You can fix your issue by using both props.fn and props.kind.
playground
Or write a type guard function.

Kotlin: Type inference failed: Not enough information to infer parameter E in fun <E> <init>(): kotlin.collections.ArrayList<E>

I declared a variable like this:
var G: Array<MutableList<Int>> = Array(0) { ArrayList() }
Kotlin gives me the following error:
Kotlin: Type inference failed: Not enough information to infer parameter E in fun <E> <init>(): kotlin.collections.ArrayList<E> /* = java.util.ArrayList<E> */
Please specify it explicitly.
It means Kotlin can't infer the type for the ArrayList which should be Int. So I add Int explicitly for the ArrayList like following:
var G: Array<MutableList<Int>> = Array(0) { ArrayList<Int>() }
Kotlin says - Remove explicit types arguments
In this case, Kotlin is ambivalent about how to act.
So is it possible to write code without explicitly declaring the type of ArrayList?
As discussed here,
The way it works curretly is that whenver we encounter a collection in Kotlin, we load a Kotlin version of this class (e.g. kotlin.Collection) instead of a Java version (java.util.*). Using the type java.util.Collection leads to a warning from the Kotlin compiler, because Kotlin's type checker is designed to distinguish between read-only and mutable collections.
So you can try to use like this,
var G = arrayOf<MutableList<Int>>()
Moreover, here are some a good stuff to know for you.
Kotlin says - Remove explicit types arguments
Kotlin doesn't (you can see there's no warning in https://pl.kotl.in/7v1h5Yobu). It's probably the IDEA plugin which does. If you look at https://youtrack.jetbrains.com/issues/KT?q=Remove%20explicit%20types%20arguments, you can see there are quite a few false positives. It may be worth checking if yours is actually one of them and posting a new issue if it isn't.
var G = Array<MutableList<Int>>(0) { ArrayList() }
should work without warning from IDEA either.

Typescript: Type assertion as any, what does this mean?

I am trying to understand how a section of code works. I have seen type assertion before but for some reason I can't wrap my head around this.
(this.whatever as any).something([]);
Larger section of code:
resetThis(): void {
if (this.whatever) {
(this.whatever as any).something([]);
}
}
When trying to run this block I get the error: this.whatever.someting is not a function
Your code is equivalent to this plain JavaScript code:
this.whatever.something([]);
When you say as any in TypeScript, you're telling the compiler to ignore the previous type of the preceding expression and instead treat it as if it were of the any type. So in your case, you're telling the compiler that this.whatever is of type any.
The any type in TypeScript is basically a type that means "we don't know anything about what this variable really is, so let me do whatever I want with it". The TypeScript handbook describes it as "opting out of typechecking".
Let's say this.whatever has type IMyType.
With:
IMyType {
prop1: string;
prop2: string;
}
so if you call this.whatever.something([]), the compiler will scream. Because the something([]) function is not defined in IMyType.
Using as any will tell the compiler that for that specific statement, it should consider this.whatever to be of type any. Which means it can have any property or method it wants.

Typescript Class.prototype.MyFunction makes errors but working

I can't explain why I get an error but code works. Is that compiler bug? (I use Visual Studio Code with Angular 2)
class A
{
fun(a: number)
{
return a+2;
}
}
A.prototype.F = function() { return "F here!"+this.fun(1); } // This makes error: The property 'F' does not exist on value of type 'A'
var a: A = new A();
console.log(a.F());
And bonus: This is not working at all! (no access to this.fun())
A.prototype.F2 = () => { return "F2 here!"+this.fun(1); } // ()=>{} is not working! cause _this is not defined!
...
console.log(a.F2());
Edit #1
As #seangwright said I need to use Module Augmentation but...
As far as it's working with simple example with my A class I can't make it work with Angular's ComponentFixture. This should solve my problem if I do this like in Typescript example:
declare module '#angular/core/testing' // I was trying without this line and with 'global' instead of '#angular/core/testing' but nothing helps
{
interface ComponentFixture<T>
{
TestOf(cssSelector: string): string;
}
}
But I still get an error:
'ComponentFixture' only refers to a type, but is being used as a value
here.'
at this point:
ComponentFixture.prototype.TextOf = function(cssSelector: string): string
{
...
}
There is even more errors, for example when I try to use it:
let fixture: ComponentFixture<EditableValueComponent>;
fixture = TestBed.createComponent(EditableValueComponent);
I got:
'ComponentFixture' is not assignable to type
'ComponentFixture'. Two different types with
this name exist, but they are unrelated. Property 'TestOf' is
missing in type 'ComponentFixture'
So again: Code works but has many compilation errors. Or maybe I'm missing something obvious?
I get the feeling you are a C# developer based on how you format your code.
Part 1
In Typescript once you declare your class, the type system expects it to have the properties (shape) you define and that's it.
The more of the type system you want to use, the less dynamic your objects will/can be.
That said, the reason your code runs (transpiles) correctly is because this is an error in the context of Typescript's structural type system, not Javascript's dynamic type system. So Typescript will tell you A doesn't have a property F at compile time, but Javascript doesn't care that it's added at runtime.
One solution is to merge the class with an interface
class A {
fun(a: number) {
return a + 2;
}
}
interface A {
F(): string;
}
A.prototype.F = function () { return "F here!" + this.fun(1); }
var a: A = new A();
console.log(a.F());
Another would be to temporarily abandon the type system
class A {
fun(a: number) {
return a + 2;
}
}
(A.prototype as any).F = function () { return "F here!" + this.fun(1); }
var a: A = new A();
console.log((a as any).F());
But that becomes verbose and prone to errors and loses the benefits that a type system brings.
You mention you are using Typescript with Angular 2. You could write in ES2015 if you wanted a more dynamic syntax. But then you will lose some of the benefits that Angular 2 gets from using Typescript (better tooling, smaller deployments).
Part 2
The reason your second example doesn't work at all has nothing to do with Typescript and everything to do with Scope (or execution context) in Javascript, specifically ES2015 arrow functions.
An arrow function does not create its own this context, so this has its original meaning from the enclosing context.
Unlike in your first example you are not using the traditional function declaration syntax and instead are using the () => {} arrow function syntax. With your first example
A.prototype.F = function() { return "F here!"+this.fun(1); }
this refers to whatever context F() is going to be executing in. Since you define it on the prototype of A it is going to be executing in the context of A. A has a .fun() method so this.fun() is going to be the same one defined in your class above.
With your second example, F2 is not going to be executing in the context of A despite being defined as a method of its prototype. The arrow function syntax is instead going to allow F2 to run in the context of the enclosing context which is the global window object unless you are running in strict mode in which case
in browsers it's no longer possible to reference the window object through this inside a strict mode function.
So this will be undefined and calling fun() on undefined is going to throw an error.
Try adding a console.log(this) to your F2 function.
A.prototype.F2 = () => { console.log(this); return "F2 here!"+this.fun(1); }
When you run the transpiled Javascript you will probably see Window logged out to the console, and then probably an error like Uncaught TypeError: _this.fun is not a function
Use the Typescript Playground to write some Typescript, see what the tooling tells you, what transpiled Javascript is created and then run it to see if your Javascript is correct.

How to serialize/unserialize an Array of Custom object in Kotlin?

In my Kotlin Android project, I made a FileItem class which extends Serializable
class FileItem(<parameters>) : Serializable, Comparable<FileItem> {
So I needed to Serialize instances of this class into a Bundle
val arguments:Bundle = Bundle()
arguments.putSerializable("folders", folders as Serializable)
where folders has been declared as :
folders:Array<FileItem> (method parameter)
The serialization code above compile without any warning. Meanwhile, the problem comes when I need to unserialize folders items :
val arguments: Bundle? = getArguments()
if (arguments != null){
foldersItems = arguments.getSerializable("folders") as Array<FileItem>
where foldersItems is declared as
var foldersItems: Array<FileItem>?
I get the following warning, that I can't manage to solve without suppress_warning annotation :
w: <Path to my class>: (78, 28): Unchecked cast: java.io.Serializable! to kotlin.Array<com.loloof64.android.chess_positions_archiver.main_file_explorer.FileItem>
This kind of code compiles in Java/Groovy without warning (folderItems is then a FileItem[]), so how can I modify the kotlin code for the compiler to be "satisfied" ?
I noticed in official Kotlin documentation that Kotlin Array does not extend Serializable and is not open for inheritance. Is it possible meanwhite to "add" it via a kind of extension method ?
In fact, the cast is not unchecked, the compiler's warning is misleading.
This happens because in Kotlin arrays are represented by generic class Array<T>, and the compiler treats it as usual generic class with type parameters erased at runtime.
But on JVM arrays have reified types, and when you cast something as Array<SomeType>, the generated bytecode really checks the type parameter to be SomeType as well as something being an Array<*>, which would only happen for any other generic class.
This example shows that the array cast is checked:
val a: Any = Array<Int>(1) { 0 }
val i = a as Array<Int>
val d = a as Array<Double> // gets checked and throws ClassCastException
The easiest solution is indeed to #Suppress("UNCHECKED_CAST"), because actually there should not be any warning.
I filed an issue describing the problem in Kotlin issue tracker.
The cast here is unchecked because the compiler here can't ensure the nullability of array's generic type parameter.
Consider the following example:
fun castAsArrayOfString(param: Any) = param as Array<String>
castAsArrayOfString(arrayOf("a")) // is Array<String>, all ok
castAsArrayOfString(arrayOf("a", null)) // is Array<String>, but contains null
So the compiler warns you about potential type safety problems this cast could introduce.

Resources