TypeScript中函数定义中的嵌套泛型

时间:2018-03-05 01:55:33

标签: typescript

我试图依靠动作类型为redux动作制作类型安全的处理程序。例如,任何操作都可以描述为:

type ActionType<T extends string> = {
  type: T
};

对于具体行动,可以:

type MyAction = ActionType<'hey' | 'there'>;

现在,我想限制一个处理程序功能,只允许&#39;嘿嘿&#39;或者&#39;那里&#39;作为一种类型。最后我希望这样的事情:

handleAction<MyAction>('hey');

其中处理函数的定义可以是:

function handleAction<A extends ActionType<T>>(type: T){
...
}

但我有一个打字稿编译错误:

  

TS2304:找不到姓名&#39; T&#39;。

所以,我必须以这种方式修改这个处理函数定义:

function handleAction<A extends ActionType<T>, T extends string>(type: T){
...
}

它有效,但看起来很丑:

handleAction<MyAction, 'hey' | 'there'>('hey');

TS Playground

有什么更好的方法可以解决这个问题?

3 个答案:

答案 0 :(得分:2)

修改

您可以使用类型查询来获取type的类型:

function handleAction<A extends ActionType<string>>(type: A ['type']) {
}

handleAction<MyAction>('hey');

或者您可以使用2.8中的条件类型从ActionType中提取通用参数(2.8在撰写本文时尚未发布,但将于2018年3月发布,您可以通过npm install -g typescript@next获取)

type ActionType<T extends string> = {
  type: T
};

type MyAction = ActionType<'hey' | 'there'>;


function handleAction<A extends ActionType<string>>(type: A extends ActionType<infer U> ? U : never) {
}

handleAction<MyAction>('hey');

此解决方案基于inference behavior of conditional typeActionType<infer U>基本上说:如果某个其他类型ActionType的{​​{1}}延伸,则为U类型。所以U将是在我们的案例中传递给U的任何字符串文字类型。然后我们在条件类型的真分支上使用ActionType,这将成为out条件类型的最终类型。在这种情况下,我们不关心假分支,所以我们永远不会使用。

答案 1 :(得分:1)

有两种方法:

  1. 使用字符串union。
  2. 我喜欢这个,因为它更简单(对于你描述的问题):

    type FileAction = 'save' | 'read' | 'copy';
    function doAction (a) {
    }
    declare function doAction<A extends string> (action: A): void;
    
    doAction<FileAction>('save'); // good, as desired
    doAction<FileAction>('xxx'); // error, as expected
    
    1. 通过括号表示法获取.type
    2. 这是一个看起来更hacky,但它是一个有效的语法..它不需要你改变你的对象形状。

      type FileFile <T extends string> = {
        type: T;
      }
      type WordFile = FileFile<'why'|'you'|'no'|'work'>;
      
      function doAction2 (a) {
      }
      declare function doAction2<F extends FileFile<string>> (action: F["type"]): void;
      
      doAction2<WordFile>('no'); // good, as desired 
      doAction2<WordFile>('xxx'); // error, as expected
      

答案 2 :(得分:0)

这清理了一些事情,但我不确定这是否是你所希望的:

type ActionType<T extends string> = {
  type: T
};

type MyWord = 'hey' | 'there';
type MyAction = ActionType<MyWord>;

function handleAction<A extends ActionType<T>, T extends string>(type: T){
}

handleAction<MyAction, MyWord>('hey');