How to use typeof in Object.prototype - node.js

I've created an object prototype, and am trying to check the 'typeof' 'this', but it always returns 'object'.
Object.prototype.testme = function() { return typeof this }
And then
'test'.testme(); // returns 'object' instead of 'string'
So in the prototype, if I add
console.log(this)
I get:
[String: 'test']
How do I just test the value with typeof in a prototype? I know I can define prototypes based on the type, but I need a catchall as there will be null values etc...?

Related

nodejs express server get request log symbols value [duplicate]

I have an object in NodeJS (a socket to be accurate).
When I print it, I see that one of the entries is this:
[Symbol(asyncId)]: 2781 // the numeric value changes
How can I obtain the value of such key?
I've tried socket['[Symbol(asyncId)]'] but got undefined.
The expression socket.[Symbol(asyncId)] would obviously not work.
You will not be able to access it directly by key, unless you have a reference to the actual: Symbol('asyncId'), because every Symbol is unique
The Symbol() function returns a value of type symbol, has static
properties that expose several members of built-in objects, has static
methods that expose the global symbol registry, and resembles a
built-in object class but is incomplete as a constructor because it
does not support the syntax "new Symbol()".
What you can do is loop through the object's own property keys, using Reflect.ownKeys, which will include normal properties & symbols, and then obtain that reference.
You can also use: Object.getOwnPropertySymbols()
function getObject() {
// You don't have access to this symbol, outside of this scope.
const symbol = Symbol('asyncId');
return {
foo: 'bar',
[symbol]: 42
};
}
const obj = getObject();
console.log(obj);
console.log(obj[Symbol('asyncId')]); // undefined
// or Object.getOwnPropertySymbols(obj)
const symbolKey = Reflect.ownKeys(obj)
.find(key => key.toString() === 'Symbol(asyncId)')
console.log(obj[symbolKey]); // 42
NOTE: The object can have multiple keys where key.toString() === 'Symbol(asyncId)', this won't be usual, but be aware, so you may want to use other function other than .find if that's the case.
NOTE II:
You should not change the value of that property, since it's supposed to be for internal access only, even if the property is not read only.
function getObject() {
// You don't have access to this symbol, outside of this scope.
const symbol = Symbol('asyncId');
const symbol2 = Symbol('asyncId');
return {
foo: 'bar',
[symbol]: 'the value I don\'t want',
[symbol2]: 'the value I want'
};
}
const obj = getObject();
const symbolKey = Reflect.ownKeys(obj)
.find(key => key.toString() === 'Symbol(asyncId)')
console.log(obj[symbolKey]); // the value I don't want
console.log('=== All values ===');
Reflect.ownKeys(obj)
.forEach(key => console.log(obj[key]));
Use Object.getOwnPropertySymbols(obj) and iterate over it
You need to store the Symbol in advance and use it as accessor for the object.
Every symbol value returned from Symbol() is unique. A symbol value may be used as an identifier for object properties; this is the data type's only purpose. Some further explanation about purpose and usage can be found in the glossary entry for Symbol.
var asyncId = 42,
symbol = Symbol(asyncId),
object = { [symbol]: 2781 };
console.log(object[symbol]);
console.log(symbol.toString());

Type check with typeof === custom type with Flow error

Given the following code:
type CustomTypeA = {
x: number,
y: number,
}
type CustomTypeB = CustomTypeA & {
z: number,
}
type CustomType = CustomTypeA | CustomTypeB
export const myFunction = (a: CustomType | number): number | void => {
if (typeof a === 'number') {
return a; // THIS WORKS WELL, it's considered number after the check, which is correct
} else if (typeof a === CustomType) {
const newX = a.x // ERR: Flow: Cannot get `a.x` because property `x` is missing in `Number`
const newZ = a.z // SAME ERR, Flow: Cannot get `a.z` because property `z` is missing in `Number`.
}
}
Also, the typeof a === CustomType check is highlighted as an error as well:
Flow: Cannot reference type `CustomType` from a value position.
This however doesn't happen for the typeof a === 'number' one.
It's like the check against the custom object type I created is not valid/recognized.
Can someone explain why and possibly how to escape this?
Thanks.
Flow custom types are not values, they do not exist, they vanish after transpilation, therefore you can not use them with a JS operator like typeof because it requires a value. So when you do typeof a === CustomType it will fail, because after compilation you will end with typeof a === , CustomType is just stripped out and you end with invalid JS.
This seems to be a flow limitation to be honest.
There is the %checks operator which allows you to build type guard functions.
One may think you can use this feature to build a type refinement for your custom types with a function that has the proper logic, but nothing on its documentation suggest that it can be used to refine custom types.
It also requires the body of the guard function to be very simple so flow can understand what do you mean. Some type guard function examples may look like this (from flow docs):
function truthy(a, b): boolean %checks {
return !!a && !!b;
}
function isString(y): %checks {
return typeof y === "string";
}
function isNumber(y): %checks {
return typeof y === "number";
}
However when you try a more complex check, for example checking that something is an object, but it is not an array or a date, flow fails to understand your intention and the predicate function will not work. Something like this:
function isObject(obj: mixed): boolean %checks {
return Object.prototype.toString.call(obj) === '[object Object]'
}
Will fail because flow doesn't understand that as a type refinement for object. For that particular case, there is a workaround suggested on a github issue that consist on declaring the function on the type level asserting that it checks for the object type:
declare function isObject(obj: mixed): boolean %checks(obj instanceof Object)
But you can not use that either for your particular case, because you can not do instanceof on a custom type, because it is not a class.
So your options are either go verbose and check all the expected properties are present on a type check, like this:
if (typeof a.x === 'number' && typeof a.y === 'number' && typeof a.z === 'number') {
const {x: ax, y: ay, z: az} = a
// now you can safely use the extracted variables
Note you need to extract the props from the object because, any time you call a function flow will invalidate your type refinement and the next line that access a.x will fail.
You can declare your point as a Class, and use the type system checking for instances of that class.
Or you build a validation function that returns either the correct type or null, so flow can understand the type has been refined:
function isCustomType (p: mixed): CustomType | null {
const validated = ((p:any):CustomType)
if (typeof validated.x === 'number' && typeof validated.y === 'number') return validated
return null
}
const validA = isCustomType(a)
if (validA) {
const {x: ax, y: ay} = validA
// do stuff
This has the disadvantage that you need to allocate extra variables just to satisfy the type system, but I think that is a minor problem.
Also, it will not allow flow to validate the isCustomType function for you, because we are doing type casts to basically cheat flow. But given the surface is small and the objective is very focused it should be ok to be able to keep it manually correct.

How to implement a type safe, phantom types based builder in typescript?

The idea is to allow a call to the .build() method only upon having all the mandatory parameters filled. So the constructor should be taught to do some validation.
If I understand you correctly, you have some kind of builder class, which by default doesn't have all the required parameters. And that class has a method, which updates its state. Only when all required parameters are set, only then build method should be available.
So first of all, we have T type which partial (all properties are optional).
On each update, we should return a new instance with type T & Record<K, T[K]> - it means optional T + one non-optional property.
Finally, we can use conditional types to allow build only when T extends Required<T>.
So the final solution:
function createBuilder<T>(initialData: T) {
return {
update: <K extends keyof T>(key: K, value: T[K]) => {
return createBuilder<T & Record<K, T[K]>>({
...initialData,
[key]: value
})
},
build: (() => {
//
}) as T extends Required<T> ? () => boolean : undefined
}
}
const builder1 = createBuilder<Partial<{
key1: string,
key2: number
}>>({})
builder1.build()
// Cannot invoke an object which is possibly 'undefined'
const builder2 = builder1.update('key1', 'abc')
builder2.build()
// Cannot invoke an object which is possibly 'undefined'
const builder3 = builder2.update('key2', 10)
builder3.build()
// No error
Hovewer, there is no point having this logic. If you can statically update the object, you probably can set all properties in the constructor.

How to pass value to property that name was passed in function parameter in TypeScript?

I'm getting eslint/typescript error:
errorUnsafe member access .value on an any value
#typescript-eslint/no-unsafe-member-access
while i try to save value to dynamic property name:
selectChange(name: string, value: string) {
if(this[name] && typeof this[name].value === "string") {
this[name].value = value
}
}
I add if-statement, but it doesn't help, is it possible to do it in proper way ? Or i have to change eslint configuration file.
Ok, i have solution:
declare in some place above:
type column = 'property1' | 'property2'
and remove unnecesary if-statement from method:
selectChange(name: column, value: string) {
this[name].value = value
}
And it will be working perfectly.

Node.js: get the original string or number from 'this' in the function call

When I wrote the codes as the below, I found that javascript will automatically convert the number or string caller (like 1 or 'str' in the codes) to object. And this perform will impact my code to compare the 'this' and the argument 'expectedValue'.
So my questions are:
how can I convert 'this' back to original number or string?
if cannot find a way to convert back, how can I check 'this' and 'expectedValue' are equal?
var mustEqual = function (expectedValue) {
console.log("typeof this:"+(typeof this));
console.log("typeof expectedValue:"+(typeof expectedValue));
console.log("is equal: "+(this === expectedValue));
}
Object.defineProperty( Object.prototype, "mustEqual", {
value: mustEqual, enumerable: false});
Object.defineProperty( Number.prototype, "mustEqual", {
value: mustEqual, enumerable: false});
if (require.main === module) {
(1).mustEqual(1);
('str').mustEqual('str');
}
The output result:
typeof this: object
typeof expectedValue: number
is equal: false
typeof this: object
typeof expectedValue: string
is equal: false

Resources