Can someone please explain, why in this code the assignment to the constant of type InterfaceA works, but the assignment to the constant of type InterfaceB throws an error:
interface InterfaceA {
doSomething (data: object): boolean;
}
interface InterfaceB {
doSomething: (data: object) => boolean;
}
function doIt (data: { type: string; }): boolean {
return true;
}
const A: InterfaceA = {
doSomething: doIt
};
const B: InterfaceB = {
doSomething: doIt
};
For an online demo, see: http://www.typescriptlang.org/play/index.html?ssl=19&ssc=1&pln=1&pc=1#code/JYOwLgpgTgZghgYwgAgJLmvJBBZBvAWAChlkATAewGUKBbCMAC1AHNkAKMuMOALmQoAjAFYQEYAJT9BFCgBsIcEAG5iAX2LFQkWIhTodWCACF8xUpRr0mrfp258BIsZOQBeAHzIZ8xSvWaRDAAriDiwBQg5BSoYBxcPPx4yGAAngAOEPwAzmBQrMrIalLesgpKZkQAkFAMwVBRecEQqkQaRMQIkbnI2PwGmHq4bpVVlnQMzCAs-JSx6q1dID3G-Ri6SKYjhNXj1lMz0fNtrUA
To me, both interfaces are defining the same, only the notation is different.
If this is not a bug in TypeScript, and there is a real reason, then let's come to my second question: I need to specify, that "doSomething" is optional and can either be a function, or a RegExp:
interface InterfaceB {
doSomething?: ((data: object) => boolean) | RegExp;
}`
How could I achieve this, with the notation of InterfaceA?
Interface can define both the kind of key an array uses and the type of entry it contains. Index can be of type string or type number. An interface can be extended by other interfaces. In other words, an interface can inherit from other interface. Typescript allows an interface to inherit from multiple interfaces.
Function Types #. Interfaces are capable of describing the wide range of shapes that JavaScript objects can take. In addition to describing an object with properties, interfaces are also capable of describing function types. To describe a function type with an interface, we give the interface a call signature.
If you do not want to specify types at all, TypeScript’s contextual typing can infer the argument types since the function value is assigned directly to a variable of type SearchFunc. Here, also, the return type of our function expression is implied by the values it returns (here falseand true).
Explore how TypeScript extends JavaScript to add more safety and tooling. Primitives Any Literals Union and Intersection Types Unknown and Never Type Primitives Tuples Built-in Utility Types Nullable Types Meta-Types Conditional Types Discriminate Types Indexed Types Mapped Types Language Soundness Structural Typing Type Guards
1.) There is a difference between method and function property declaration:
interface InterfaceA {
doSomething(data: object): boolean; // method declaration
}
interface InterfaceB {
doSomething: (data: object) => boolean; // function as property declaration
}
2.) TypeScript 2.6 introduces a compiler flag for stronger-typed, sound function types:
Under
--strictFunctionTypes
function type parameter positions are checked contravariantly instead of bivariantly. The stricter checking applies to all function types, except those originating in method or constructor declarations. (my emphasis)
So in general that is a good thing. In your example, InterfaceB
has following contract: "Every function that can deal with a general object
is compatible". But you want to assign a function doIt
, that expects specific objects of type { type: string; }
as input. A client that uses InterfaceB
thinks, it is enough to pass object
, but the implementation doIt
wants something more concrete, so you rightfully get that error.
InterfaceA
?In contrast, methods like doIt
in InterfaceA
are excluded from --strictFunctionTypes
for practical reasons. The developers decided the type system to be not too pendantic with built-in methods of Array
etc. to have a reasonable balance between correctness and productivity.
So, in favor of stronger types, I would prefer the following type, which works for your case (sample):
interface InterfaceB {
doSomething: ((data: { type: string; }) => boolean) | RegExp;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With