Forcing an optional interface property to be defined - javascript

Say I have the following interface:
interface Example {
optionalString?: string
// ... other props
}
And I have a function taking a Example as a parameter. I know the return type syntax is bogus.
function ensureDefined (example : Example) : Example & {optionalString: string}
The idea of this function is to ensure that the property optionalString of example is defined and that object returned. In which case, every time I wish to access the optionalString property, I don't need to do an if(example.optionalString){}.
I have tried creating an extension of the interface like so:
interface ExampleExtension extends Example {
optionalString: string // notice no '?'
// ... other props
}
But then this one is not assignable back onto a variable with a type of the base interface.
Am I overcomplicating this? Should I just have two separate variables with two different types?

The interface extension works for me on the playground. If it still doesn't work for you, please add code sufficient to reproduce the problem to the question.

Related

Typescript Implements

I am new to Typescript and ran into the following question when trying to implement a interface in a class:
interface TestInterface {
x: number
}
class Test implements TestInterface {
constructor() {
this.x = 0
}
}
// Class 'Test' incorrectly implements interface 'TestInterface'.
// Property 'x' is missing in type 'Test' but required in type 'TestInterface'.
But if I add x: number to Test before constructor, it works. So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself. Then what is implement and the interface for? And if I want to use the interface to check the type of its instances, wouldn't it be repetitive since I have to write it in two places?
Code in a constructor is not something that Typescript can check to determine if your class correctly implements the interface. It would be impossible for Typescript to check all the assignments in your code to ensure the types are correct, so you need to declare the types statically. The point of interface and implements is not to reduce the amount of code you have to write, it's to declare the type of objects in your code, so that Typescript can statically check that your code is self-consistent with regard to types.
By saying the class implements the interface, you are effectively asking Typescript to keep you honest and check that the types are indeed consistent. If Typescript merely trusted that you'd do the right thing in your constructor, it would not be very effective! Note that constructors may contain conditional logic, loops and other code that mean it is not possible even in principle for Typescript to analyse the constructor code to determine if you are keeping the contract you commit to with implements.
So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself.
You are exactly right!
Then what is implement and the interface for?
An interface is intended to be a "contract". Here's a simple example:
interface Connectable {
connect: () => Promise<void>
}
const robustConnect = async (connection: Connectable) => {
try {
await connection.connect();
} catch (error) {
console.warn(`there was an error, let's try once more`);
await connection.connect();
}
}
In this example, we've typed the function robustConnect so that it can receive just any object that has a connect method. This is the most useful usage of an interface: giving a name to a type so that it is more legible.
In other OO languages, an interface would be the only way to declare a type like that, and you would have to extend the interface to use robustConnect. Otherwise, the compilation step would fail. Since javascript isn't inherently an object-oriented language and is dynamically typed, that restriction isn't there. So the implements keyword can feel useless. At best, you could use it to help yourself when writing classes: just use the implements keyword and let the TypeScript compiler tell you what you are missing. But that's about it.
Hope this helps.
Low key You need to learn Object Oriented Programming. Your question is a core principle of oop.
When you find a new job, you sign a contract, the contract specifies your role, duties, behavior and more; so you need to follow the contract so if you implement an interface your class need to follow the structure of your interface.
If for instance you find that redundant instead of creating a class use pure objects
const obj:Obj ={
name: “eneto”
};
Plus also your statement “But if I add x: number to Test before constructor, it works. So I am guessing if you wanted to check the type of a property initialized in the constructor, you have to specify that on the class itself. Then what is implement and the interface for?” doesn’t have sense, because typescript checks your code at compilation fase, but once your code compiles it becomes JavaScript which doesn’t have static types

Typescript: how can I have completion for dynamics method/functions of a class (registered at runtime)?

I have searched everywhere but didn't get a clue on how I can achieve such a behavior. I'm new to typescript, thus forgive me if it's a dumb question.
The code below is a very simplified version of what I'm looking for:
const library = { // could also be a class if necessary
registerMethod(name: string, method: () => any): void {
this[name] = method;
}
}
library.registerMethod('couldBeWhatever', () => { }); // could be called any number of times with custom functions and names
I'm looking for a way (not necessarily the one above) to register methods of a class or object at startup with allowing completion on those dynamic functions anyway. Is that possible in typescript ?
I'm guessing that by "at runtime" you mean that you want the compiler to perform control flow anlysis to try to predict what methods will be available by examining TypeScript code that calls libray.registerMethod(). Obviously there is no way to get completion in your IDE for anything that will only be known about at runtime, such as if your code generated a random method name string with Math.random() or pulled the method name from user input or API response or something.
If so, then you might want to use assertion functions. An assertion function narrows the type of one of its arguments (you can also have an assertion method that narrows the type of the object on which it is called).
By narrowing, it means that the apparent type after the assertion function must be a subtype of the apparent type before the assertion function. For example, you can't make an assertion function turn a string into a number, but you can make it turn a string | number into a number. So one of the caveats of using control flow analysis to model mutation of library is that it cannot be used to make it incompatible with the original type. Your registerMethod() method looks like it will add new members to library, and adding members to an object type is a form of narrowing. But if you needed an alterMethod() that say, changes the type of the registered method from () => string to () => number, you wouldn't be able to do this.
Here's an example implementation of library with registerMethod() as an assertion method:
interface _Lib<T extends Record<keyof T, () => any>> {
registerMethod<K extends string, M extends () => any>(
name: K,
method: K extends keyof T ? T[K] : M
): asserts this is Library<{
[P in K | keyof T]: P extends K ? M : P extends keyof T ? T[P] : never
}>
}
type Library<T extends Record<keyof T, () => any>> = T & _Lib<T>;
const library: Library<{}> = {
registerMethod(this: Library<any>, name: string, method: () => any): void {
this[name] = method;
}
}
There's a lot going on in there, but the basic idea is that library starts off as a Library<{}>, with only a registerMethod() method. When you call registerMethod() on a Library<T> with a name of type K and a method of type M, the compiler will narrow that Library<T> to something like a Library<T & Record<K, M>>. Meaning that, in addition to having registerMethod() and whatever was in T, it now also has a member at key K whose type is M.
You can test that it works:
library.registerMethod('couldBeWhatever', () => "hello");
console.log(library.couldBeWhatever().toUpperCase()); // HELLO
library.somethingElse; // error, somethingElse does not exist
library.registerMethod('somethingElse', () => 123);
console.log(library.couldBeWhatever().toUpperCase()); // still HELLO
console.log(library.somethingElse().toFixed(2)); // "123.00"
Hooray, it works! There are caveats that go along with assertion functions, though, which may or may not matter for your use case.
First of all, in order to use an assertion function you need it or the object you call it on to be manually annotated and not inferred. That's why I had to literally annotate library above as being Library<{}>. This is currently a design limitation of TypeScript. See microsoft/TypeScript#36931 among others, for more information.
Next, as with all control flow analysis narrowing in TypeScript, the compiler isn't all-knowing. It does not perform control flow analysis by simulating all possible ways to run the program and seeing which possible type narrowings stay true in all scopes. It would be prohibitively expensive to do so. Right now, what the compiler does is: when you cross a function boundary, the compiler resets any control flow narrowings. This is a reasonable trade-off, since the compiler cannot generally figure out when a function body will be called with respect to code outside the function body, or vice versa. See microsoft/TypeScript#9998 for a discussion about this issue.
What it means for the above code: when you register methods with library, you will be able to use them afterward in the same function scope. But you cannot use them "afterward" in some arbitrary other scope like a function body or some other module:
library.registerMethod('somethingElse', () => 123);
function oops() {
library.somethingElse() // the compiler doesn't know about this
}
The compiler really doesn't know that by the time oops() is called, somethingElse will have been registered on library. Actually I don't know it either without examining all of the code everywhere in the program.
A workaround for this would be to do all your registering somewhere, and then "freeze" the type of the resulting library by "saving" it into a new const variable.
const registeredLibrary = library;
function okay() {
registeredLibrary.somethingElse(); // the compiler does know about this
}
That works because registeredLibrary was created as a copy of library in a scope where methods had been registered on it already. There's no place in the code where registeredLibrary fails to have those two extra methods, so the compiler is happy to use them inside the okay() function body.
It is quite possible that the above caveats make this not work for you. The compiler is quite powerful, but unable to handle analysis that needs to happen all at once everywhere for all possible ways the code can run. But assertion methods can at least go some of the way toward modeling this kind of "dynamic" behavior.
Playground link to code

TypeScript: extract generic type from a typed function

I'm working on wrapping a function in a customized one in TypeScript. For that, I want to correctly pass down the types.
I looked at similar questions like this one, but they all seem to answer the question on how to extract from a class but not a function.
I think en example is the easiest explanation:
// we have a given function like this:
function genericFunction<T extends object>(a: T) {
return a;
}
// we want to extract the T type to pass it down for smth like this:
type ExtractedT = typeof genericFunction<IWANTTHEGENERICTYPE>; // (THIS IS WHERE I DON'T KNOW HOW TO PROCEED);
function myGenericFunction<T extends ExtractedT>(a: T, b: string) {
console.log(b, "- is a newly introduced variable.")
genericFunction<T>(a);
}
Of course, the example is a highly abstracted example, but my goal should hopefully be clear.
I appreciate your answers!
EDIT:
I updated the example since it didn't really make sense before. My goal is to "dynamically" wrap a method from a framework i.e. (my sophisticated use case also extracts the Parameters<> types, but that's smth else.)
So I guess my goal is to have a way of detecting the generic types of a function and copying them over to my own function. But I start to think this that this blows the scope of TypeScript and just hovering over the generic types and importing / copy-pasting them for the wrapper function might be the better solution

Best way to solve typescript error - property does not exist on type

I have several different situations where I am trying to define a self made property on an array or object in typescript but commonly get the error:
"Property x does not exist on type Object (or type Array)"
For example I am using typescript in Angular and have a defined scope based on the Angular type definition file:
scope:ng.IScope
But then when I try to create a new property on scope by doing:
scope.anotherProperty = "string";
I get the error mentioned above. I know I can solve it by doing one of the following:
scope["anotherProperty"] = "string";
OR
(<any>scope).anotherProperty = "string;
Another example is when I have something like this within my d3 graph:
function panZoomNode (node:any) {
for (var i = 0; i < renderedNodes.length; i++) {
if (node.id === renderedNodes[i].id) {
}
}
}
Ideally, I would like to change that (node:any) parameter to something like:
(node:Object)
But when I do that, I get an error saying "property id does not exist on type Object". I know I can correct it with the solutions I mentioned above but that seems kind of sloppy to me. Is there a better way or best typescript way of getting those to run correctly for both arrays and objects?
Thanks
You can add the extra property to the ng.IScope interface by adding the following to your code:
interface ng.IScope {
anotherProperty?:string;
}
This would allow you to call
scope.anotherProperty = "string";
Without seeing the rest of your code and knowing what node actually represents I can only say that to make the compiler happy you need to just include the members you refer to in your TS code. If you were doing it properly then create a class that contains all members. If it derives from an existing class or implements an existing interface then you should inherit from those in your class definition.
Edit: If you haven't already, you should look in the DefinitelyTyped GitHub repo for the D3 definitions. Assuming node is a D3 type, you can use that to solve your problem and avoid writing your own class.

What's the type of this object? And where is it documented?

I'm not finding what's the type of this "xpcomInterface", and there's no documentation of any class with this name. Any idea?
This snippet is from Mozilla's website:
var next = elements.item(i+1);
var xpcomInterface = scroll.boxObject.QueryInterface(
Components.interfaces.nsIScrollBoxObject);
xpcomInterface.ensureElementIsVisible(elements);
--update
I found boxObject that leads to nslBoxObject, but it have no reference to any QueryInterface as used above. There's also references to xulplanet.com which is no more there.
Well, xpcomInterface is just the name of the variable.
You should read about XPCOM and XPCOM interfaces. QueryInterface() is a method that all XPCOM objects must implement and gives you the possibility to "cast" an object to a certain interface:
(...) The function QueryInterface() is a function provided by all components which can be used to get a specific interface of that component. This function takes one parameter, the interface that you want to get. (...)
In this example, there is some object scroll.boxObject (update: which is a nsIBoxObject as you found out. Note that this again is just an interface (starts with nsI)) that seems to implement the nsIScrollBoxObject interface. By using QueryInterface, you can access those interface's methods like ensureElementIsVisible.

Categories