为什么TypeScript无法检查函数的返回类型

oyalhi

我有一个应该返回的函数NetworkState; 但是,从代码中可以看出,在大多数情况下,该函数未返回正确的类型,但TypeScript没有给出错误。我想念什么?

第二次更新:谢谢大家的投入。我已尽可能地复制和简化了代码,完整的代码已复制并粘贴到TypeScript游乐场。不幸的是,我必须包括所有类型才能重现该问题,因此代码比我希望的要长一点。请查看我认为应该有错误(由于返回类型)而没有错误的最后一行。

非常感谢您的任何帮助,谢谢。

更新和说明:

范例1:

const someFunction = (): string => 45

上面函数的返回类型为,string但是我们正在返回一个数字,因此TypeScript给出了一个错误:Type '45' is not assignable to type 'string'

范例2:

type MyType = {
    [key: string]: string | undefined
}

const someFunction = (): MyType => 45

上面函数的返回类型为,MyType但是我们正在返回一个数字,因此TypeScript给出了一个错误:Type '45' is not assignable to type 'MyType'

以下代码的问题:

在下面的示例中,networkStateReducer预期返回NetworkState类型。但是,即使它返回的数据不符合NetworkState,也仍然没有错误。

例如,如果我们仔细观察第一个case

case NetworkActionType.Failure:
      return { ...state, [action.payload.sagaAction]: 'SHOULD_BE_ERROR' }

假设state最初是空对象,则返回值为:[action.payload.sagaAction]等于某个字符串,但签名清楚地将其设置为对象:

  [key in NetworkSagaAction]?: {
    networkError?: Error
    networkStatus: NetworkStatus
  }

但是,我们没有从TypeScript得到任何错误。

实际代码:

export type NetworkSagaAction = 'Login' | 'Logout'

export type NetworkStatus = 'idle' | 'pending' | 'failure' | 'success'

export enum NetworkActionType {
  Busy = 'Network/Busy',
  Failure = 'Network/Failure',
  Idle = 'Network/Idle',
  Reset = 'Network/Reset',
  Success = 'Network/Success',
}

export type NetworkState = {
  [key in NetworkSagaAction]?: {
    error?: Error
    networkStatus: NetworkStatus
  }
}

export interface NetworkPayload {
  sagaAction: NetworkSagaAction
}

export const initialState: NetworkState = {}

type FunctionType = (...args: any[]) => any

interface ActionCreatorsMapObject {
  [actionCreator: string]: FunctionType
}

export type ActionsUnion<A extends ActionCreatorsMapObject> = ReturnType<A[keyof A]>

export interface Action<T extends string> {
  type: T
}

export interface ActionWithPayload<T extends string, P> extends Action<T> {
  payload: P
}

export type BusyAction = ActionWithPayload<NetworkActionType.Busy, NetworkPayload>

export function createAction<T extends string, P>(type: T, payload: P): ActionWithPayload<T, P>
export function createAction<T extends string, P>(type: T, payload?: P) {
  return payload === undefined ? { type } : { type, payload }
}

export type NetworkActions = ActionsUnion<typeof NetworkActions>
export const NetworkActions = {
    busy: (payload: NetworkPayload): BusyAction => createAction(NetworkActionType.Busy, payload),
}

const networkStateReducer = (
    state = initialState,
    action: NetworkActions,
): NetworkState => { 
    return {
        [action.payload.sagaAction]: 'THIS SHOULD BE OBJECT BUT NOT AND STILL NO TYPE ERROR'
    }
}
er

TypeScript无法正确推断返回类型是什么,networkStateReducer()因为您将返回具有计算值的对象,该对象的具体值要到运行时才能知道。实际上,您以这样的方式编写它:不可能推断返回的对象结构是什么(因此不可能抛出TS警告)。

仅考虑功能networkStateReducer()

const networkStateReducer = (
    state = initialState,
    action: NetworkActions,
): NetworkState => { 
    return {
        [action.payload.sagaAction]: 'THIS SHOULD BE OBJECT BUT NOT AND STILL NO TYPE ERROR'
    }
}

在这里,action.payload.sagaAction将是type NetworkSagaAction,两个字符串之一,Login或者LogoutTypeScript知道从此函数返回的对象可以具有与类型匹配的可选NetworkSagaAction,因此它可以检查这些键。但是,不知道这些键处的对象应该是什么。本质上,很容易根据编写的静态代码来推断的类型,但是该上的的类型要等到运行时才能推断出来,因为它取决于键值。

这里的事情让您有些困惑,因为两个值的类型应该是相同的:

export type NetworkState = {
  [key in NetworkSagaAction]?: {
    error?: Error
    networkStatus: NetworkStatus
  }
}

但是,假设两个值的类型实际上不同的情况:

export type NetworkState = {
  Login?: {
    error?: Error
    networkStatus: NetworkStatus
  }
  Logout?: string
}

现在,再次查看原始函数的代码:

const networkStateReducer = (
    state = initialState,
    action: NetworkActions,
): NetworkState => { 
    return {
        [action.payload.sagaAction]: 'THIS SHOULD BE OBJECT BUT NOT AND STILL NO TYPE ERROR'
    }
}

此函数的返回类型有效还是无效?如果值action.payload.sagaActionLogin那么它是无效的,因为,而不是字符串应该是一个对象。但是,如果值为,Logout则返回类型有效,因为字符串可以。那是什么呢?谁知道!(直到运行时)

从理论上讲,现在您可能会认为,如果编写代码以确保对象的所有键都具有相同的类型,那么TypeScript应该能够推断出这一点。通过执行以下操作,我们甚至可以使其更加明确:

export type NetworkSagaActionValue = {
  error?: Error
  networkStatus: NetworkStatus
}

export type NetworkState = {
  [key in NetworkSagaAction]?: NetworkSagaActionValue
}

但这似乎并不能解决问题。TS开发人员可能有一些非常聪明,复杂和故意的原因,为什么这不起作用。也许这只是将来会解决的疏忽或错误。

现在,我看到您有两个主要选项,它们都涉及到简单地networkStateReducer()稍微更改功能。

您可以像下面这样从函数返回中强制实施对象值的类型:

const networkStateReducer = (
  state = initialState,
  action: NetworkActions,
): NetworkState => { 
  const returnValue: NetworkSagaActionValue = 'THIS SHOULD BE OBJECT BUT NOT AND STILL NO TYPE ERROR';
  // 'returnValue' errors because types don't match
  return {
      [action.payload.sagaAction]: returnValue
  }
}

或者,有些罗word,但根据您的需求可能会更好-只需检查action.payload.sagaActionand的值并从那里分支,即可单独显式定义返回的对象:

const networkStateReducer = (
    state = initialState,
    action: NetworkActions,
): NetworkState => { 
  switch (action.payload.sagaAction) {
    case "Login":
      return {Login: 'THIS SHOULD BE OBJECT BUT NOT AND STILL NO TYPE ERROR'};
      // above return errors because types don't match
    case "Logout":
      return {Logout: {networkStatus: 'idle'}};
  }
}

我很想知道自己是否有仅与计算的值更优雅的方式来解决这个问题的一种方式,但据我所知是没有的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么Typescript不要求我的函数返回某个类型?

为什么此功能无法进行类型检查?

为什么Typescript无法推断此函数的参数类型?

在返回从函数的返回类型派生的类型的本地对象时,为什么未选择move构造函数?

为什么在实现通用接口时TypeScript无法推断函数参数的类型?

为什么在python3中未检查返回类型?

为什么GHC无法对该涉及多态性和存在性类型的函数进行类型检查?

当无法预期时,TypeScript函数通过类型检查

无法满足Typescript类型函数的返回类型

为什么此TypeScript代码无法进行类型检查?

在TypeScript中,为什么我的类型别名返回错误?

为什么TypeScript无法推断此JSX工厂的返回类型?

为什么要在TypeScript中声明“ any”返回类型?

为什么TypeScript的类型检查器认为通用对象的属性不能是函数?

为什么TypeScript类型不能检查React props?

TypeScript:从函数中返回_.orderBy,要使用什么返回类型?

如果构造函数无法返回null,为什么初始化后需要进行类型检查?

为什么Swift的类型检查系统允许返回类型的函数不返回任何内容?

为什么在使用区分类型检查时无法打字稿推断出返回类型

为什么TypeScript错误地推断返回类型?

为什么TypeScript类型不检查算术运算?

为什么TypeScript无法推断递归函数的类型

返回 AsyncFunction 的 Typescript 函数的适当返回类型是什么?

为什么我的函数的返回类型是 a -> Int

TypeScript:为什么函数可以返回值,尽管它的类型不允许?

检查函数的返回类型

为什么 TypeScript 不能推断出这个函数的返回类型?

为什么 TypeScript 在推断函数的返回类型时不会自动使用文字类型?

为什么 TypeScript 不报告“错误”的函数返回类型