【问题标题】:How can I correctly type functions in object using Typescript here?如何在此处使用 Typescript 在对象中正确键入函数?
【发布时间】:2021-06-15 23:56:20
【问题描述】:

我正在将一个 JS 项目转换为 TS,在这里我遇到了这个错误(使用 urql):

A function whose declared type is neither 'void' nor 'any' must return a value. ts(2355)上线:

playerCreate: (result, args, cache): UpdateResolver => {

为什么?

const updates = {
  Mutation: {
    playerCreate: (result, args, cache): UpdateResolver => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    },

    playerDelete: (result, args, cache, info): UpdateResolver => {
      // using result, args, cache here
    },
  },
};

我可以看到Updateresolver 是这样声明的:

export declare type UpdateResolver = (result: Data, args: Variables, cache: Cache, info: ResolveInfo) => void;

更新

有人正确地告诉我,我是说这个函数返回一个UpdateResolver,而类型是函数而不是返回类型。

因此问题:

如何在此处正确输入playerCreateplayerDelete

【问题讨论】:

  • playerCreate方法中弄清楚你想要返回什么(在JS逻辑中),然后返回它,然后改变UpdateResolver类型来匹配它。目前还不清楚你想要那里的 JS 逻辑。
  • TS 不知道result, args, cache, info。我想告诉它:“那个函数类型是UpdateResolver!”。只是我不知道怎么...
  • 这能回答你的问题吗? Type definition in object literal in TypeScript
  • @FredHors 这是一个分配了箭头函数的属性,而不是真正的方法。 { foo: "hello" }{ bar: () => {} } 在语法上是等效的:具有属性的对象,您可以在其中为属性分配值。副本显示了如何给这样的东西一个类型 - 要么键入 the object 要么做一个类型断言。后者与您已经得到的答案相同。
  • @FredHors @VLAZ 关于键入对象的说法是写const updates: {Mutation: Record<string, UpdateResolver>} = {... 并从各个函数中删除类型。您还可以在对象之外编写函数并将其拼凑在一起。 const playerCreate: UpdateResolver = (.... 然后 const updates = { Mutation: { playerCreate, playerDelete }, }, }; 问题是如果不使用 as 断言,您不能同时设置属性并声明该属性的类型(这可能很危险,因为它是覆盖,而不是检查) .

标签: typescript


【解决方案1】:

试着把代码改成这样:

const updates = {
  Mutation: {
    playerCreate: (result: Data, args: Variables, cache: Cache): void => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    },

    playerDelete: (result: Data, args: Variables, cache: Cache, info: ResolveInfo): void => {
      // using result, args, cache here
    },
  },
};

编辑:我发现使用as 运算符实际上是可能的:

const updates = {
  Mutation: {
    playerCreate: (((result, args, cache) => {
      const playersQueries = cache
        .inspectFields("Query")
        .filter((x) => x.fieldName === "players");
      playersQueries.forEach(({ fieldName, arguments: variables }) =>
        cache.invalidate("Query", fieldName, variables)
      );
    }) as UpdateResolver),

    playerDelete: (((result, args, cache, info) => {
      // using result, args, cache here
    }) as UpdateResolver),
  },
};

TypeScript 中的as 运算符是什么?

它告诉 TypeScript 编译器认为运算符之前的表达式具有运算符之后的类型。你可以用它做一些奇怪的事情:

const test = "some string" as number;
// "test" is number here!!

所以要小心使用它!当你将它应用于函数时,TypeScript 会看到 e. G。参数一应该具有T类型,所以它假装该函数也接受T类型的参数。

as 有一个替代方案,但不能在 TSX 文件中使用:

const something = <number>"hello";
// don't do that if you don't know the actual type!

当然这个例子是错误的,因为 TypeScript 会认为字符串是一个数字,但事实并非如此。但它显示了类型断言的用法。

【讨论】:

  • 是的,这是我想避免的:result: Data, args: Variables, cache: Cache): void,因为我可以使用UpdateResolver 类型。
  • 很抱歉,这是不可能的。创建函数后不能键入函数。
  • "但它显示了类型转换的用法。" 它显示了类型 assertioncasting 类型是不同的,而不是 as(或 &lt;&gt; 语法)所做的。类型转换是指您在 在运行时 获取一个值并在 在运行时 更改其类型。由于 TS 仅在编译时运行,因此不可能进行类型转换。例如,在 Java 中,您可以将 float 转换为整数 (int) 3.14,这将为您提供 3
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 2021-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多