Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript does not detect type error

Tags:

typescript

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?

like image 477
Manfred Steiner Avatar asked Feb 04 '23 22:02

Manfred Steiner


2 Answers

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.

like image 199
Aviad Hadad Avatar answered May 29 '23 12:05

Aviad Hadad


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.

like image 34
Titian Cernicova-Dragomir Avatar answered May 29 '23 12:05

Titian Cernicova-Dragomir