如何使TypeScript正确键入对泛型函数的检查调用,然后依次调用具有泛型类型参数的函数?

时间:2019-02-15 03:48:31

标签: typescript

我正在尝试编写与此非常相似的代码:

const globalState = {
  searchState: {
    id: "value"
  }
};

interface MapState<Result> {
  (state: any): Result;
}

interface SearchState {
  id: string;
}

interface HasSearchState {
  searchState: SearchState;
}

const createUseMapState = <State>() => {
  return (mapState: MapState<State>) => mapState(globalState);
};

const useHasSearchState = createUseMapState<HasSearchState>();

const useSearchState = (mapState?: <T>(state: SearchState) => T) => {
  if (mapState) {
    return useHasSearchState((hasState) => mapState(hasState.searchState));
  }
  return useHasSearchState((hasState) => hasState.searchState);
};

const useId = () => useSearchState((state) => state.id);  // <-- Error here!

CodePen中可用。

TypeScript(3.3.3)在最后一行给出TS2345:

Argument of type '<T>(state: SearchState) => string' is not assignable to parameter of type '<T>(state: SearchState) => T'.
  Type 'string' is not assignable to type 'T'.

如果我将最后一个功能更改为不使用中间功能,则可以使用:

const useId = () => useHasSearchState((state) => state.searchState.id);  

如何声明useSearchState函数的类型,以便在useId类型检查中使用它?

React库的帮助下,使用Hooksredux-hooks是真实代码的上下文。

我觉得应该正确输入check,但是显然我误会了一些东西。

1 个答案:

答案 0 :(得分:1)

将T参数提升到外部函数。

const a = (m: <T>() => T) => { 
  return m();
}
// Type 'string' is not assignable to type 'T'
a(() => 'Hey!');

但是

const a = <T>(m: () => T) => { 
  return m();
}
// Ok!
a(() => 'Hey!');

让我们更改您的代码

const useSearchState = <T>(mapState?: (state: SearchState) => T) => {
  if (mapState) {
    //                       Type 'T' is not assignable to type 'HasSearchState'.   
    return useHasSearchState((hasState) => mapState(hasState.searchState));
  }
  return useHasSearchState((hasState) => hasState.searchState);
};

类型检查器现在可以使用,useHasSearchState的类型为(mapState:MapState)=> HasSearchState。添加限制:

const useSearchState = <T extends HasSearchState>(mapState?: (state: SearchState) => T) => {

现在很明显错误

// Type 'string' is not assignable to type 'HasSearchState'.
const useId = () => useSearchState(state => state.id);