【问题标题】:Typescript specify return or type of function is not the sametypescript 指定返回或函数类型不一样
【发布时间】:2019-12-19 11:21:52
【问题描述】:
const a1: () => { a: string } = () => {
  return {a: '', b: ''} // not erroring!?
}

const a2 = ():{ a: string } => {
  return {a: '', b: ''} // is erroring as expected
}

const a3: () => { a: string } = () => {
  return {b: ''} // is erroring as expected
}

游乐场:https://www.typescriptlang.org/play/?ssl=15&ssc=2&pln=11&pc=2#code/MYewdgzgLgBAhgRgFwwBQEoYF4B8MDe8K0ATgJZgDmMAvtmprgQFAwwkCmUAriWAXBQByIQBoYAI2FC6AelkwwIWBxIkQ5KgEIA-MxrNmoSLDgAmehiSFBMUhWp0m+Vuy69++WyPFSYIuQUyCBhVdU1qOBCOAA8ABw5gKA4AE31DY2h4AGYUDGw8G2IoCNpLRkLXTh4+Aj8AmHkYYNC1DQd4aPjE5LSaIA

这两个应该是一样的,但不知何故 a2 有一个打字错误。

我的代码以 a1 的格式完成(定义了函数)并且没有出错。如果不正确,我想知道如何处理错误。

正如您在 a3 中看到的,它出错了。所以它仍在检查类型,但不如 a2 中准确。好诡异。

“打字稿”:“^3.7.2”

Error in ide

interface State {a:string}
const similarToRealWorldIssue: (state:State ) => State  = (state) => {
  return {...state, b: 'ssda'} // here I meant to put `a`, but I put `b` by mistake and nobody complained.
}

【问题讨论】:

  • 我认为在第一种情况下,您将 ():{a:string, b:string} 分配给 ():{a:string} 类型的变量,这没有错,但在第二种情况下如果您定义 ():{a:string} 然后继续返回 is 错误的 {a:string, b:string}。
  • 但是看看a3,它是错误的。根据您的解释,a3 应该不会出错。
  • 在第三种情况下,您尝试将 ():{b:string} 分配给 ():{a:string} 类型的变量,这是错误的,因为您无法从 { b:string},但您可以从 {a:string, b:string} 中提取它。
  • 那么a1和a2的返回类型是什么?如果你检查是完全一样的。但他们的行为不一样。我在文档中看不到任何地方,这取决于您定义函数的方式将匹配返回或仅包含返回。没有意义海事组织
  • a3 没有错,因为它返回 {b:string} 而是因为您将返回 {b:string} 的东西分配给期望返回 {a:string} 的变量并且有{b:string} 中没有 a:string。

标签: typescript


【解决方案1】:

您的similarToRealWorldIssue 函数可以分为两部分。

第一部分,

const similarToRealWorldIssue: (state:State ) => State

声明并指定similarToRealWorldIssue 的返回类型为State

第二部分,

    = (state) => {
      return {...state, b: 'ssda'}
    }

这是一个没有明确定义返回类型的函数,因此返回any。 typescript 编译器不会抱怨,因为类型 any 也可能是 State

您可以通过两种方式解决此问题。

解决方案 1:将 State 指定为箭头函数第二部分的返回类型。

    const similarToRealWorldIssue: (state:State ) => State  = (state): State => {
      return {...state, b: 'ssda'}
    }

解决方案 2:首选解决方案,因为它简化了您的功能并使其更易于阅读。

    const similarToRealWorldIssue = (state: State): State => {
      return{
        a: '',
      }
    };

在这种情况下,任何不需要的附加字段都会产生编译器错误,同样遗漏必填字段。

希望这会有所帮助。

【讨论】:

  • 谢谢,但我已经知道我可以把State 放在最后,但这不是最佳选择,因为它不是 DRY。正如我所说,我有一个所有这些函数都必须遵循的接口,并且在每个函数上添加返回类型很容易出错。
【解决方案2】:

本质上,第一种情况发生的情况是这样的:

const a1_anon = () => {
  return {a: '', b: ''} // not erroring!?
}
// inferred type of a1_anon is () => {a: string, b: string}
const a1: () => { a: string } = a1_anon

如果你不希望它发生,你需要指定类型,这样它就不会被这样推断:

const a1: () => { a: string } = (): {a: string} => {
  return {a: '', b: ''} // not erroring!?
}

我知道它被指定了两次,但由于您坚持定义一个匿名函数,然后将其分配给变量,所以没有其他办法。

当然,您可以采用定义 a2 的方式,因为它不会两次指定类型,而是执行您需要的操作,但您已经知道了。

对于您的具体问题,您可以使用a2 定义事物的方式。如果State 接口不是太大,那么您总是可以将所有值分配给返回的State 对象,这样,如果您输入错误的内容,它将是缺少的属性而不是额外的属性(这里的... 用法是无论如何,我认为有问题)。另一种方法是定义一个函数并在返回State 对象时始终使用它。

const statify = (state: State): State => { return state }
const exampleUsage: (state: State) => State = (state) => {
  return statify({...state, c: '' })
}

你可能想用 getter 和 setter 方法定义一个 State 类并使用它而不是任意对象。也不确定是否要始终复制状态并更改其属性,但如果这样做,您可以在该类中实现一个方法来制作副本。

想到另一个选项,这会将{...state, <properties>} 更改为stateAdd(state, {<properties>})

interface State { a: string, b: string }
interface StateAddition { a?: string, b?: string }
const stateAdd = (state: State, additional: StateAddition): State => {
  return { ...state, ...additional }
}
const exampleUsage: (state: State) => State = (state) => {
  return stateAdd(state, {c: ''})
}

【讨论】:

  • 谢谢,但我有许多这些功能应该添加到适当的 API 中,这样做容易出错并导致大量重复,这是我试图避免的。跨度>
  • 他们确实遵守 API 只是有额外的属性,就接口而言这很好。您将能够以您期望的方式使用这些返回的对象,这样在编译器的眼中就可以了。
  • 是的,但是我刚刚发现了一个错误,因为我输错了一个键并且没有错误。这适用于一系列减速器,所以我需要使用 ... 扩展运算符,因此将添加正确的属性 + 错误类型的属性。
  • 您能否分享一个更相关的代码示例来解决您发现的错误,以便我们尝试解决那个问题?
  • 我添加了一个例子similarToRealWorldIssue
猜你喜欢
  • 2017-03-09
  • 2015-03-23
  • 1970-01-01
  • 2021-05-13
  • 2020-04-27
  • 2020-06-09
  • 2018-07-07
  • 2021-01-03
  • 1970-01-01
相关资源
最近更新 更多