Manfred Steiner
Manfred Steiner

Reputation: 1295

Typescript does not detect type error

I have the following code snippets:

File router-data.ts#L46

...
const fd = FroniusMeter.getInstance(req.query.address ? req.query.address : 1);
....

The method getInstance() is defined in file fronius-meter.ts#L51

public static getInstance (id: string): FroniusMeter {
    if (id.startsWith('/dev')) {
        debug.info('...');
    }
    let rv = ModbusDevice.getInstance(id);
    if (!rv) {
        rv = ModbusDevice.instances.find( (d) => (d instanceof FroniusMeter) && (d.address === +id) );
    }
    return rv instanceof FroniusMeter ? rv : null;
}

The sources are transpiled without warning or error (tsconfig.json), but executing throws an exception TypeError: id.startsWith is not a function.

The reason is clear, the call of getInstance() uses a number as parameter, but the method is written for a string as parameter. Therefore id.startsWith(... throws an error.

My question, why did typescript transpilation not print out some warning or error?

Upvotes: 9

Views: 973

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250246

The reason this passes is very simple, and comes from the type of req.query which is any. Since this is any any property access will also be of type any. So req.query.address is of type any.

If conditional the two branches of a conditional expression have different types the conditional expression type will evaluate to the union of the two

let x = Math.random() > 0.5 ? "A" : 0; // x is string | number

However in a union any will always eat up any other types so a conditional in which either branch has an any will be typed as any

let y: any;
let x = Math.random() > 0.5 ? y : 0; // x is any

So in your call req.query.address ? req.query.address : 1 is of type any and thus assignable to string.

And this is why any should be avoided like the plague especially by library writers.

Upvotes: 4

Aviad Hadad
Aviad Hadad

Reputation: 1717

The reason is simple, req.query is defined as any. So req.query.address is also defined as any.

let's take this code:

let f: TypeA;
let g: TypeB;
let bool: boolean;
let x = bool ? g : f;

Typescript will infer the type of x to be TypeA | TypeB.

So, the type of the expression req.query.address ? req.query.address : 1 is technically any | number, however this is just any.

In typescript 3.0 a new type called unknown is supposed to be added, which should solve this.

Upvotes: 7

Related Questions