variable with interrogation point at the end [duplicate] - javascript

I've seen code snippets like these:
export interface IUser {
email?: string;
firstName?: string;
lastName?: string;
}
But why are the variable names suffixed by a question mark? This snippet is part of an example of using mongodb with Typescript.
The answer is probably somewhere out there but I seem to be using the wrong keywords since I can't find it.

In TypeScript, <name>?: <typename> a shorthand for <name>: <typename> | undefined.
This indicates to the type system that a symbol may contain a value of the indicated type or it may contain the value undefined (which is like null).
This is important when the (new in TypeScript 2) --strictNullChecks option is enabled. The documentation on Null- and undefined-aware types option is probably where you should start to understand why this is useful.

It means they can be there but dont have to be. It allows for optional field names. It can be quite common to use.
An example use is allowing users on a website to have an optional display name.

If I am not mistaked, its to indicate that its optional, that means that it can be null.

Related

Declaring object property type in function param

This problem has me so confused, I don't even know how to properly title this question.
I started learning TypeScript a couple of hours ago and I've run into a brick wall with a Property 'whatever' does not exist on type 'object'. intellisense error.
I get the feeling that I'm supposed to declare an interface for this object that defines the property in question, but that feels wrong, since the object is an event listener parameter, so I don't call the function directly - the library that I'm using does. It also feels like an interface for something that I'll literally only use once is overkill.
Let me show you what I mean:
// this event listener is created by the library I'm using, so I can't change the params it sends
this.load.on('fileprogress', (file: object) => {
console.log(`Loading asset: ${file.key}`); // ".key" is crapping out with "Property 'key' does not exist on type 'object'."
});
The easiest solution seems to be just doing (file) => {...} so that it defaults to type any, but I want to avoid that, otherwise I might as well go back to using plain old JavaScript. The next thing I came up with is declaring interface File { key: string } above the event listener and then changing the function to (file: File) => {...}, but that feels like a hack because, like I said, I'm not the one calling this function and have zero control over what's actually getting sent as the parameter. Also, the whole interface File... feels overly verbose.
What I was thinking, along the interface lines, is isn't there some way to inline declare the properties' types in the parameter list. Something like (file: object { key: string })? This will still be a hack if we think of it literally as an inline interface, but at least we're now telling it what properties the object is expected to have, right?
One thing I came up with which isn't throwing an intellisense error is this monstrosity (file: {[key: string]: any} = {}) => {}, but there's that dreaded any keyword again, and intellisense is reporting this as a... Well, I don't even know what it's supposed to be. Here's a screenshot.
I guess the bottom line question that I'm asking is what's the correct way to handle this type of situation where a function that you don't call directly needs to receive an object with properties you can't predict and thus can't define?
The idiomatic TypeScript typing for this is Record<string, unknown>. That assumes that you will receive an object with string property names, but assumes nothing about specific property names or what types their values might have. You will then need to perform runtime narrowing tests in order to safely access any property of this object. So, for example:
this.load.on('fileprogress', (file: Record<string, unknown>) => {
if (typeof file.key === 'string') {
console.log(`Loading asset: ${file.key}`);
}
});
(Note that the typeof guard here is not necessary to simply say .key, as a Record object will allow any string property name. It is necessary to confirm the value's existence and type [I guessed string]).
However, are you sure that the library you are using makes absolutely no representation about the shape of the object it passes to you? That seems unusual even for a plain JS library. Many, if not most, libraries even have their own TypeScript typings now (either directly or through #types/* packages), making these argument types implicit.

Angular #input property ending with exclamation point?

This source code has #Input properties that end with a !. Here's an example:
#Input() token!:StripeToken
Why is it useful to have the ! in this case? Some of the comments have noted that it is a non null assertion operator, but why is it useful (Or perhaps not useful) to have that in this particular scenario?
I think the answer to this is that for Angular #Input properties having the non null assertion at the end of the property never makes sense but I wanted to see what the rest of you thought?
Update
I tried it on a new Angular project and I get this error:
A definite assignment assertion '!' is not permitted in this context.ts(1255)
So I don't think that it ever makes sense to inlude the ! operator on an #Input property. Here's a screenshot:
They use the compiler option strictPropertyInitialization so any class property not declared with type undefined and not initialized directly or in a constructor produces error TS2564.
To prevent this compiler error they use the definite assignment assertion modifier which tells TypeScript
... that a variable is indeed assigned for all intents and purposes,
even if TypeScript’s analyses cannot detect so.
Demo
Further reading: https://mariusschulz.com/blog/strict-property-initialization-in-typescript#solution-4-definite-assignment-assertion
Regarding your update
You didn't specify a type for the title variable in your example, that's why you get error TS1255. Using ! in this context is possible and makes sense!

I can't understand this strange JS Flow syntax

I'm trying to remove some JS Flow typing syntax from an application, but I can't seem to refactor this certain line accurately. It's part of a class declaration:
declare class Error {
static (message?:string): Error;
static call(x: any): void;
static captureStackTrace(x: any, x: any): void;
name: string;
message: string;
stack: string;
}
The problematic line is static (message?:string): Error;.
What is this line doing, and how can I rewrite it without Flow?
It looks like a method but has no name.... Any help would be appreciated!
It's a declaration of a factory function, just merged with class declaration.
So you can type check this: const error = Error(message).
To be less confusing, it can be rewritten as constructor (message?: string): Error.
Then you'll need to use new: const error = new Error(message).
Here is the example of both ways - try flow
So, without flow, you just need to write a function that returns Error object, and maybe check its first argument to be a string if not undefined.
I am not a pro in flow, but i'll try to answer your questions.
What is this line doing
The method accepts an optional string variable named message and it returns an Error object.
how can I rewrite it without Flow?
I think you can use typeof to check the type of the variable. You can find more information here
For my understanding, this definition is to check the input type of primitive Error Object.
This kind of Flow semantic is called library definition which is used to define type check for 3rd party library. You could see the definition below.
Flow defintion
So what you need to do is create a customized Error function say myError and check the first argument type as string. Then return Error Object.

Flow type, What does the `+` symbol mean in front a property?

I came across the following code written in js FlowType (I am interested to know the value of + in the context of FlowType not in general JS).
Could you please explain me what does the + symbol mean in front of the property in the code below:
export type User = {
+name: string,
+surname: string,
+personId: PourceId,
}
I could not find any reference in the documentation, any link is also welcome.
The + symbol in front of the property means the property is read-only
Reference: https://flow.org/en/docs/types/interfaces/#toc-interface-property-variance-read-only-and-write-only
The '+' symbol means the property is read only and
'-' means the property is write only and If does not have any '+' or '-' symbol it means the property have both read/write access. It can be used while defining interface property or type property.
The documentation can be found in below link:
https://flow.org/en/docs/types/interfaces/#toc-interface-property-variance-read-only-and-write-only
After some additional research I found out that +/- indicate the covariant or contravariant for a property.
interface MyInterface {
+covariant: number; // read-only
-contravariant: number; // write-only
}
Interesting article on variance:
https://flow.org/en/docs/lang/variance/
https://flow.org/en/docs/types/interfaces/#toc-interface-property-variance-read-only-and-write-only

Why does Typescript allow to assign an "any" object type to class object?

I have a class object:
groupNameData: GroupNameData = new GroupNameData();
and I have an any object
groupNameDatas: any;
Assignment 1 (class = any)
I just assigned the class object values to any object, like
this.groupNameDatas = this.groupNameData;
It means, this.groupNameDatas (Any) can accept any kind of data, because it's an any object.
Assignment 2 (any = class)
Now I have reversed the assignment, like
this.groupNameData = this.groupNameDatas;// any to class
It's also working like my first assignment example. Why it did not throw an error like cannot convert implicitly "any" to "GroupNameData"?
This is the expected behavior (docs). Hopefully this sample will clarify it:
let someObj = new MyClass();
// someObj will be of the "MyClass" type.
let anyObject : any;
// since anyObject is typed as any, it can hold any type:
anyObject = 1;
anyObject = "foo";
// including your class:
anyObject = someObj;
// so, if it can hold anything, it's expected that we can assign our custom classes to it:
someObj = anyObj;
But how can typescript accept to assign any object to class object?
That's the fun with the any type. Typescript can't know if your any-typed variable holds an instance of your object or not. It's anything, so it could be an instance of your object.
If you look at the official documentation, it clearly says that with "any" all compile time checks are ignored.
Relevant snippet from the docs:
We may need to describe the type of variables that we do not know when we are writing an application. These values may come from dynamic content, e.g. from the user or a 3rd party library. In these cases, we want to opt-out of type-checking and let the values pass through compile-time checks. To do so, we label these with the any type:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
The any type is a powerful way to work with existing JavaScript,
allowing you to gradually opt-in and opt-out of type-checking during
compilation. You might expect Object to play a similar role, as it
does in other languages. But variables of type Object only allow you
to assign any value to them - you can’t call arbitrary methods on
them, even ones that actually exist:
Should you choose to use another type e.g. number or string the
compile time checks kick in and you know that its not right.
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
The any type is also handy if you know some part of the type, but
perhaps not all of it. For example, you may have an array but the
array has a mix of different types:
let list: any[] = [1, true, "free"];
list[1] = 100;
You can read about unknown - this is the type-safe counterpart of the any type.
Here is a link with the differences.
TypeScript needs a different way of thinking from a traditional statically type language. In languages like C# or Java the compilar gives a type error unless the programer has provided enough information to make clear to the compiler it should not give a type error. In Typescript the compiler only gives a type error if the programer has provided enough information for the compiler to know the types are not valid.
The use of Any takes information away from the compiler.
Typescript was created to allow the incremental addition of type information with as many bugs in the program being found at compile as the type information allows. It can be thought of as a "super lint" that takes advantage of any type information that is provided.
Over the years Typescript has moved closer to what people (like me) who are used to strict compile time type checked languages expect, but it great stenth is that it still, "fits in" well with Javascript.

Categories

Resources