TS: How to get interface from a dynamically created object - javascript

I have a schema object that contains the typed property that starts empty.
const schema = {
typed: {},
// ...
}
schema.typed will be filled dynamically when the application starts, example
typed['name'] = 'Yung Silva'
typed['age'] = 22
in another moment
typed['facebook'] = 'fb.com/yungsilva'
typed['whatsapp'] = 81981355509
there is no pattern, really each time the application is started it will be a totally different and random structure.
I would like to get an interface for this object that was dynamically assembled, example
type Fields = typeof schema.typed
it is possible?
is disturbing me at the beginning, at the moment to create the object dynamically, I don’t know what type to define for schema.typed

This is not possible since Typescript "checks" your types at compile time.
"The goal of TypeScript is to help catch mistakes early (before running the code, at compile time) through a type system and to make JavaScript development more efficient." more
At runtime the code that runs is a normal (sorta) javascript code.
there are several libraries (typescript-is) that can help you check types at run time, but the common use case doesn't need them.

TypeScript is about type checking ahead of runtime. Its purpose is to check the code consistency with itself and the third party library it uses, before running it. TypeScript won't be able to assign a type depending on the actual data, because it simply doesn't exist anymore at run time. When you write will be a totally different and random structure that means you're using plain JavaScript and its dynamic nature, so if your data never has common parts, just don't type it at all (or as any).

Related

Is there any way to access existing visual studio type data or vscode extension outputs?

I'm currently trying to write my own VSCode extension.
The purpose of this extension is to compare types of HTML Custom Attributes and javascript code expressions.
Now, it's completely possible to get the type of HTML attributes, there are NPM packages and as long as they're documented via JSDoc or have proper types using typescript - no problem.
but now look at the following example:
/** #param {MyPage} page */
export function renderSomePage(page)
{
return html`
<my-component .my-attribute="${page.SomeProperty}"></my-attribute>
`
}
the question now is, how do I get the type of the expression ${page.SomeProperty}? This is the main question i want to solve with this question.
I have some ideas.
visual studio does already know what type this expression is. Because when i hover over the parts of this expression, then i get a hover showing me the type. So ideally i want to receive some kind of Dictionary of tokens mapped to types that VSCode must have somewhere
there's always the typescript/javascript language support plugin in VSCode that probably does all that work for the IDE. I'd need to get exactly those compiling/parsing results to get to the type of this expression
of course there are also corner cases, where it's not that simple. I also need to be able to evaluate expressions like:
(args) => result
identfiier.function()
primitive types (string, number, boolean)
arrays of complex types
anonymous objects
arrays of anonymous objects
You didn't mention anything about an LSP, which tells me that that is what your missing.
Bellow is in reference to idea #1 in the question:
The type information that you see when hovering is generated by the "TS LSP", which stands for...
"TypeScript Language Server Provider"
What you want to do is use a feature called "Request Forwarding" to access the information already present, which is provided by the VSCode LSP.
I believe that the node Language server provides features for TypeScript, and always runs in the background. This is because VSCode runs in a Node RTE, and it has built-in features that are written in TypeScript. If you were writing a language like Go (or Go) per-say, then you would need to call to that specific language server.
You can use the "VS Code Language API", which makes requests to language servers. The API is written to work with language server that adheres wholey to the "Language Server Protocol". to access the "Programmatic LSP Features".
VSCode has a few examples that demonstrate how to use the LSP.
Really, you have two options, you can...
...parse TypeScript yourself, write grammars for the embedded mark-up, pull out all the type info, and write the type checking software you intend to write, or you can...
...use the already existing LSP to access the info, which includes requests for type info, and then write the type-checking software.
Hopefully that points you in the write direction.

Typescript and REST API response

Let me preface this question by saying that I am fairly new to typescript, but a long time JavaScript developer.
I have an existing JavaScript application that I am looking to transition over to typescript. In the JavaScript app, it makes a rest API call to fetch data, then checks to see if it exists, and then conditionally renders the app. In JavaScript, I can dynamically check to see if Properties exist on the response object and conditionally render that. In typescript, it throws an error because the data is of any type, and it doesn’t know if that property exists or not.
In a typescript application, is it pretty common to go create types for all of your API responses, so that you can get type safety on them? Using node as your backend, I could see a huge opportunity where you might be able to share backend and front end models. I am currently using .net core for my backend, and I am concerned I might be shooting myself in the foot trying to always create typescript models from the entity framework models.
Does anyone else use .net core for the backend and react on the front end? How do you handle API responses in typescript?
I can't tell you if it's common, but we write json-schema files for every endpoint. These schema files are:
Used to validate request bodies and generate errors.
Used to generate documentation.
Converted in to typescript types, which are used in both front- and backend.
We are using the same stack as you--.Net Core backend/React frontend--with typescript. The way we handle it is by creating types for the objects the backend sends us and then converting the dynamic checkers, like the ones you mention, into user-defined type guards.
So, roughly speaking, for the various data transfer objects the server returns we have a type/type guard pair that looks like this:
// type
export type SomeDto = { someKey: string; someOtherKey: number }
// type guard
export const isSomeDto = (returnedObj: any): returnedObj is SomeDto =>
returnedObject.someKey && typeof returnedObj === "string"
returnedObject.someOtherKey && tyepeof returnedObj === "number"
Then we have basically have the following in the fetching code:
const someReturn = fetchDatafromApi(endpoint)
if isSomeDto(someReturn) {
//now typescript will recognize someReturn as SomeDto
} else {
// throw or otherwise handle the fact you have bad data from the
// server
}
This way you get the dynamic checking in javascript at runtime and type safety at compile time. These guards aren't super-fun to write (and you'll want to unit test them all), and I imagine if the possible number of objects was bigger we'd opt for a more automated solution like #Evert mentions in the other answer. But for a few objects, and existing javascript validators, it is a pretty convenient way to get typing on your API returns.

Instantiating a class dynamically from a string

Good afternoon fellow developers,
I am currently trying to develop a function that instantiates business objects dynamically based on the value of the string it receives as a parameter. I know this can be done in JavaScript as I have done it before and, just to be sure, I even tested it again in Visual Studio Code after having encountered this issue in my SAPUI5 app. My function's code looks somewhat like this:
createObject: function (sObject) {
var newObject = new this[sObject]();
// var newObject = new [sObject](); I also tried this way.
};
For the sake of testing this function, the sObject string currently contains the hardcoded value "Order" and I am importing my Order.js object into the file where i'm trying to instantiate this objects dynamically. No matter what I try I keep getting this error when debugging my code:
TypeError: this[sObject] is not a constructor
I was wondering if some of you might have tried something similar before and might be able to point me in the right direction. Even if there are ways for me to work around this issue, it would be really nice if I learnt how to do this dynamically since I was planning on using this approach on several different scenarios. I look forward to reading from you!
It is a really unsafe practice to instantiate objects from a string and an ATROCIOUS one to do it from a parameter a user can supply. If you have a limited set of objects its much safer to have a big switch statement.
switch(name) {
"objA": return new ObjA();
}

compile time required function parameter checking

Is there a best practice way of enforcing parameters in functions at build time vs runtime? For example if i have following function:
function localize(strings, key, ...args) {
return ...
}
and I called it as such:
var result = localize('myKey')
I did not pass the first parameter ('strings'). I would like to throw a compile error and not wait until runtime to get the error.
Because Javascript is not compiled, and dynamically typed, there is no way to enforce the contract in your example except at runtime.
However, you can use a build system like Typescript, Flow, etc, to add type annotations to your code. These require a compilation step BUT the issue you have in your example would be caught by both during that step.
Without that, there is no way to get what you want as far as I know. The best you could do in vanilla javascript is to validate the arguments you are given inside the localize function, and use logs/errors so that you can easily identify the issue when you test your code locally. The important bit here is that without actually running your code, there is no way to catch the error in your example using vanilla JS.

Flow type annotations and valid JavaScript source

I'm playing with Facebook's new Flow Type checking system.
In Flow, meet Underscore it appears that they change this JavaScript code
var root = this;
into this
var root: any = this;
But this is no longer valid JavaScript, right? I understand why external Interface files would be useful, but how are type annotations added directly into valid JavaScript sources?
Previously, Google Closure compiler and other projects used on JS comments.
As of Flow 0.4.0 you are able to put the Flow syntax into the comments. This solves your issue. So your example would look like:
var root/*: any*/ = this;
This results in valid JavaScript syntax and there is no need to transpile your code.
Further details can be found here:
http://flowtype.org/blog/2015/02/20/Flow-Comments.html
You're right, that code is no longer valid javascript. That means that when you use Flow in someJavascriptFile.js, you have to execute a program that removes the Flow code from someJavascriptFile.js, which is called transpiling. Which transpiler to use depends on how you're running javascript, and will probably change over time, so I won't link to any.
You can also wrap the flow types into a comment, eg. var name /*:string*/ = "Hello flow.", which is valid javascript, but makes the code harder to read in my opinion.
In theory, Javascript engines could one day natively support Flow parsing, but that's a long ways off.
I missed Running Flow code where it discusses adding a build step to remove type annotations.
You can use the JSX transform tool (part of the React tools) to
translate your files to plain JavaScript
I also found flow-typestrip which is alternative.
I like external interface files per module better, as you can avoid introducing a build step.

Categories

Resources