Open dguttman-jacada opened 4 years ago
I guess my question is what happens if two variables did this?
declare var hello: string | number;
redeclare var hello: number;
redeclare var hello: string;
@DanielRosenwasser my answer would be:
function foo(input: string | number): string {
if (typeof input === "string") {
return input; // here input is string
} else {
return number.toString(); // here input is number
}
}
so in your example, hello
would end up a string
(if the code is processed sequentially)
It makes sense for the redeclare
to be scoped, so if the variable was redeclared within a function body (or any other relevant scope), the redeclaration would be valid for the scope of the function body. e.g for an express app:
app.get("/", (req, res, next) => {
redeclare req: typeof req & { myProp: string };
req.myProp = Guid.generate();
asyncOp((res) => {
res.send(res.req.myProp);
});
});
req.myProp = ""; // error - req does not have a 'myProp' property
in JavaScript it is also possible to do:
// file1.js
var hello = 123; // essentially declare it as a number, would work with declare var hello: string | number;
// file2.js
var hello = "foo"; // essentially declare it as a string, would work with declare var hello: string | number;
// file3.js
var hello = false; // essentially declare it as a boolean, would *not* work with the above and would need to be redeclared - in most cases: redeclare var hello: typeof hello | boolean;
currently there is no way to describe this with TypeScript
Came here for a mildly different reason, closer related to issue https://github.com/microsoft/TypeScript/issues/14306, some variables were "declared" in the global scope, but I chose to explicitly make them into variables.
ex:
const { Map } = self;
const func = () => {
const variable = new Map{...};
// Map cannot be overrode via devtools or such
}
Someone I was working with had actually noticed that global lookups were slowing down their code, so I tried to test this, but TS didn't like it.
cross-linking to #4062
redeclare
can have other benefits:
I have a "header" type of interface:
export interface api_msg_t {
a:string;
devid:string;
}
function is_api_msg(m:any) :m is api_msg_t {
return (
m && typeof(m)=="object" && typeof(m.a)=='string' && typeof(m.devid)=='string'
)
}
I want to have extended interface:
interface api_node_online_t extends api_msg_t {
a:"onl";
nid:number;
state:node_state;
}
function is_api_node_online(m:api_msg_t) : m is api_node_online_t {
return (m.a=='onl' && typeof(m.nid)=="number" && is_node_state(m.state));
}
if there is no inex type in api_msg_t
the typeguard is_api_node_online
fails to transpile as m.nid
does not exist in api_msg_t
. But adding index in the api_msg_t
propagates it to api_node_online_t
that is undesirable. if we can do
function is_api_node_online(m:api_msg_t) : m is api_node_online_t {
redaclare m as api_msg_t & {[index:string]:unknonw};
return (m.a=='onl' && typeof(m.nid)=="number" && is_node_state(m.state));
}
It will allow for elegant and typesafe solution.
We can easily mimic this behavior with
interface api_msg_indexed_t extends api_msg_t {
[index:string]:nknown;
}
function is_api_msg_indexed(m:api_msg_t):m is api_msg_indexed_t:{
return true;
}
function is_api_node_online(m:api_msg_t) : m is api_node_online_t {
if (!api_msg_indexed(m)) return;
return (m.a=='onl' && typeof(m.nid)=="number" && is_node_state(m.state));
}
but this results in unnecessary JS code emitted and ran
Search Terms
redeclare variable, re-declare variable, augment variable, merge variable declaration, declaration override
Suggestion
define a
redeclare
keyword which allows re-declaration of a typed variable. e.g.Use Cases
When an external library declares a variable, e.g.
The
redeclare
keyword can be used somewhere else to override the declaration:or augment it:
This would allow to type the pure JavaScript case of:
Examples
to extend the variable with additional static methods to
URLSearchParams
is not possible currently (see here).The feature can be used in the following way:
Checklist
My suggestion meets these guidelines: