“提供的参数与目标的调用签名不匹配”的简单打字稿示例

时间:2017-06-29 01:48:37

标签: javascript typescript

我正在学习Typescript并且一直在研究这个例子:

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))

对于x(someObj),func函数的return语句和最后一行func调用中的x都得到相同的错误。

这是错误:

  

提供的参数与目标

的呼叫签名不匹配

但是,如果我使用已编译的版本并将其粘贴到控制台中,则可以通过记录'字符串表示字符串'来工作。

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

我正在使用Typescript Playground中的编译器:

https://www.typescriptlang.org/play/index.html

我已经查看了有关此错误的stackoverflow的其他问题和答案,但它们似乎与更复杂的Angular问题有关,我不理解它们。

1 个答案:

答案 0 :(得分:1)

为了扩展您的评论,对于Andrew Li的(应该是什么)正确答案,您实际上已经将自己锁定在您创建的角落中,通过OVER-TYPING。

通过明确键入所有内容,您可能看起来非常安全,但实际上您提供了额外的空间来解决不一致问题。

如果func看起来像:

function func (obj: Thing, x): string {
  return x(obj);
}

根据您的版本和设置,它可能工作得很好(或抱怨&#34;没有任何隐含的&#34;)。

你所做的是为它提供一种不匹配的类型,因为你只想提供一个一次性来安抚系统。

我不是说听起来对抗,或任何事情;我们都为此感到愧疚。但需要安抚类型系统让我们一直都很邋。。

我认为看待它的痛苦方式就是这样:

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);

如果您要在VSCode中加载它,我相信您会对从中获得的类型信息感到惊喜。

类型实际上是为了方法签名的好处 如果您想要在它们周围使用工具,请随意添加类型信息到consts:

const obj: Thing = { a: 1, b: true, c: "Yes" };

但这并不是它最有益的地方;特别是因为即使obj具有不同的类型,例如OtherThing,如果它也符合x的标准,它仍可以进入funcThing,即使它与它无关,也对它一无所知。

为了使这更为一般:

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);

如果你犯了任何类型的错误,它会对你大喊大叫,而且,你仍然会用仍然经过严格类型检查的文字来调用函数。

想要什么东西?

const g = <A, B>(o: A, x: Transform<A, B>):B => x(o);
const d = g({ a: 1, b: true, c: "" }, x);

您没有告诉g ANYTHING 它正在处理的类型。它是一个匿名函数,具有匿名类型,可以进行转换。

仍然知道返回d的类型,仍然知道oThing(无论它是什么类或它有什么接口)。它知道这一点,因为它从x中提取了这些类型并向后工作。

所以现在你有:

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);

仍然d正确 使用这样的类型对你来说似乎是违反直觉的,但是你可以通过依靠类型推理的优势,在正确性方面实际上做自己的大好处,而不是依靠手动使类型系统满意的额外噪音这可能与它认为应该具有的内容相冲突。