打字稿:获取具有通用参数的函数签名的更多目标返回类型

时间:2019-11-19 10:38:49

标签: typescript

我有以下几种类型

interface AutosuggestState<Item> {
  highlightedIndex: number | null
  inputValue: string | null
  isOpen: boolean
  selectedItem: Item | null
}

interface ItemToString<Item> {
  (item: Item): string;
}

interface AutosuggestProps<Item> {
    itemToString?: ItemToString<Item>;

    highlightedIndex?: number | null;
    inputValue?: string | null;
    isOpen?: boolean;
    selectedItem?: Item;

    initial?: {
        highlightedIndex?: number | null;
        inputValue?: string | null;
        isOpen?: boolean;
        selectedItem?: Item;
    }

    default?: {
        highlightedIndex?: number | null;
        inputValue?: string | null;
        isOpen?: boolean;
        selectedItem?: Item;
    }
}

这是代码

const defaultStateValues: AutosuggestState<null> = {
  highlightedIndex: -1,
  isOpen: false,
  selectedItem: null,
  inputValue: ''
}

function getDefaultValue<
  I,
  P extends AutosuggestProps<I>,
  K extends keyof AutosuggestState<I>
>(
  props: P,
  statePropKey: K
) {
  if (props.default && typeof props.default[statePropKey] !== "undefined") {
    const ret = props.default[statePropKey]
    return ret as Exclude<typeof ret, undefined>;
  }
  return defaultStateValues[statePropKey]
}

function getInitialValue<
  I,
  P extends AutosuggestProps<I>,
  K extends keyof AutosuggestState<I>
>(
  props: P,
  statePropKey: K
) {

  if (statePropKey in props && typeof props[statePropKey] !== 'undefined') {
    const ret = props[statePropKey]
    return ret as Exclude<typeof ret, undefined>
  }

  if (props.initial && typeof props.initial[statePropKey] !== 'undefined') {
    const ret = props.initial[statePropKey];
    return ret as Exclude<typeof ret, undefined>
  }

  return getDefaultValue(props, statePropKey)
}

function getInitialState<
  I
>(
  props: AutosuggestProps<I>
): AutosuggestState<I> {

  const selectedItem = getInitialValue(props, 'selectedItem')
  const highlightedIndex = getInitialValue(props, 'highlightedIndex')
  const isOpen = getInitialValue(props, 'isOpen')
  const inputValue = getInitialValue(props, 'inputValue')

  return {
    highlightedIndex,
    isOpen,
    selectedItem,
    inputValue,
  }
}

function useAutosuggest<
  I
>(
  userProps: AutosuggestProps<I>
){
  const initialState = getInitialState( userProps );
}

问题

  1. 如果您在TS Play上打开此代码,则会发现

getInitialValue函数中的getInitialState调用正在抱怨,例如

const highlightedIndex = getInitialValue(props, 'highlightedIndex')

props投诉–

Argument of type 'AutosuggestProps<I>' is not assignable to parameter of type 'AutosuggestProps<unknown>'.

类似地,getDefaultValue内部的getInitialValue调用

return getDefaultValue(props, statePropKey)

props抱怨同样的事情。

我无法找出函数getInitialValuegetDefaultValue的正确类型,这些函数将正确地合并从I传递的泛型类型useAutosuggest。基于控制流的类型,我无法正确编写。

  1. 除了initialState以外,selectedItem的类型不正确(在下面的行中)
  const initialState = getInitialState( userProps );

/**
    initialState is of type 

    highlightedIndex: number | null; ✅
    isOpen: boolean; // ✅
    selectedItem: unknown; // should come I | null
    inputValue: string | null; ✅
*/
  1. 如何将I函数中的useAutosuggest泛型以及由此函数调用流程中的每个地方都限制为特定约束(它可以是对象或字符串,没什么)

  2. 给出了代码,我是否键入错误或执行不正确的操作?可以输入更好的东西来使这段代码更好吗?

2 个答案:

答案 0 :(得分:0)

设置默认类型,如下所示:

function getDefaultValue<
  I = any,
  P extends AutosuggestProps<I> = AutosuggestProps<I>,
  K extends keyof AutosuggestState<I> = keyof AutosuggestState<I>
>(

function getInitialValue<
  I = any,
  P extends AutosuggestProps<I> = AutosuggestProps<I>,
  K extends keyof AutosuggestState<I> = keyof AutosuggestState<I>
>(

playground

答案 1 :(得分:0)

我尝试了几种方法,并找到了我认为最好的方法。 由于Item中的object | string,因此您无法将itemToString设置为AutosuggestProps。函数参数需要满足contravariant。将Item设置为object | string时,将违反此规则。所以我尝试了palyground

最良好的祝愿。