Reputation: 10732
I'm learning Typescript and have been working on this example:
interface Thing {
a: number;
b: boolean;
c: string;
}
let obj = <Thing>{
a: 5,
b: true,
c: 'string that says string'
}
function x(someObj: Thing): string {
return someObj.c;
}
function func(someObj: Thing, x: () => string) {
return x(someObj);
}
console.log(func(obj, x))
I get the same error for both x(someObj), which in the return statement in the func function, and the x within the call to func in the last line.
This is the error:
Supplied parameters do not match call signature of target
However, if I take the compiled version and just paste it into the console it works by logging 'string that says string'.
var obj = {
a: 5,
b: true,
c: 'string that says string'
};
function x(someObj) {
return someObj.c;
}
function func(someObj, x) {
return x(someObj);
}
console.log(func(obj, x)); //string that says string
I'm using the compiler in the Typescript Playground:
https://www.typescriptlang.org/play/index.html
I have looked at other questions and answers on stackoverflow with this error but they seem to relate to more complicated Angular questions and I do not understand them.
Upvotes: 0
Views: 203
Reputation: 26696
To expand upon your comment, to Andrew Li's (what should be) correct answer, you've actually locked yourself in a corner that you created, by OVER-TYPING.
It may look like you're being extra-safe, by explicitly typing all of the things, but you're actually providing extra space to let inconsistencies in.
Had func looked like:
function func (obj: Thing, x): string {
return x(obj);
}
it might have worked just fine (or complained about "NO IMPLICIT ANY") depending on your version and your settings.
What you did was to provide it a type which didn't match, because you just wanted to provide a throwaway to appease the system.
I don't mean to sound confrontational, or anything; we're all guilty of it. But needing to appease type systems makes us sloppy all the time.
I'd argue that the less painful way to look at it would be like this:
interface Transform<A, B> {
(x:A):B;
}
interface Thing {
a: number;
b: boolean;
c: string;
}
type ThingC = Transform<Thing, string>;
const x = (obj: Thing) => obj.c;
const func = (obj: Thing, x: ThingC) => x(obj);
const c = func({ a: +!0, b: !0, c: "I work fine." }, x);
If you were to load that up in VSCode, I'm sure you would be pleasantly surprised with the type information you get from it.
Types are really for the benefit of method signatures.
Feel free to add type information to consts, if you want tooling around them, of course:
const obj: Thing = { a: 1, b: true, c: "Yes" };
But that's not really where it's most beneficial; especially because even if obj
had a different type, like OtherThing
, it could still go into x
or func
if it also met the criteria of Thing
, even if it has nothing to do with it, and knows nothing about it.
To make that an even more general case:
interface Transform<A, B> {
(x:A):B;
}
interface Apply<A, B> {
(x:A, f: Transform<A, B>):B;
}
interface Thing {
a: number;
b: boolean;
c: string;
}
const x: Transform<Thing, string> = obj => obj.c;
const f: Apply<Thing, string> = (obj, x) => x(obj);
const c = f({ a: 1, b: true, c: "" }, x);
It's going to yell at you if you make any type mistakes, and still, you're calling functions with literals that are still being rigorously type-checked.
Want something zany?
const g = <A, B>(o: A, x: Transform<A, B>):B => x(o);
const d = g({ a: 1, b: true, c: "" }, x);
You didn't tell g
ANYTHING about what types it was dealing with. It's an anonymous function, with anonymous types, which is handed a transform.
It still knows what type is getting returned into d
, and it still knows that o
is a Thing
(regardless of what class it is or what interface it has). It knows this, because it pulled those types from x
and worked backward.
So now you have:
interface Transform<A, B> { (x:A):B; }
interface Thing { a: number; b: boolean; c: string; }
const x = (obj: Thing) =>
obj.c;
const g = <A, B>(o: A, x: Transform<A, B>):B =>
x(o);
const d = g({ a: 1, b: true, c: "" }, x);
And it still gets d
right.
Using types like this might seem counter-intuitive to you, but you can actually be doing yourself big favours, in terms of correctness, by leaning on the strengths of type inference, rather than leaning on manually making the type-system happy with extra noise that might conflict with what it thinks it should have.
Upvotes: 1