【问题标题】:How to get a subset of `keyof T` whose value, T[K] are callable functions in Typescript如何获取“keyof T”的子集,其值 T[K] 是 Typescript 中的可调用函数
【发布时间】:2018-12-27 09:16:45
【问题描述】:

我想根据T[keyof T] 的类型过滤keyof T

它应该像这样工作:

type KeyOfType<T, U> = ...

KeyOfType<{a: 1, b: '', c: 0, d: () => 1}, number> === 'a' | 'c'

KeyOfType<{a: 1, b: '', c: 0: d: () => 1}, string> === 'b'

KeyOfType<{a: 1, b: '', c: 0: d: () => 1}, Function> === 'd'

这可能吗?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    您可以使用映射类型的as 子句来过滤类型的键:

    type KeyOfType<T, V> = keyof {
        [P in keyof T as T[P] extends V? P: never]: any
    }
    
    

    映射类型的as 子句允许我们操作键的名称。如果键映射到never,则键将从结果类型中删除。你可以在这个PR找到更多信息

    前 TS 4.1

    这个版本在 4.1 后仍然有效,只是其他方式更容易阅读。

    您可以使用条件类型和映射类型来做到这一点

    type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]
    

    让我们稍微分解一下。

    我们可以从映射类型开始,它具有与原始T 相同类型的相同属性,这是一个简单的标准映射类型:

    type KeyOfType<T> = { [P in keyof T]: T[P] } // New Type same as the original
    

    T[P] 是一个类型查询,表示T 类型中的键P 的类型。我们可以将其更改为 P,这意味着新属性的类型与其名称相同:

    type KeyOfType<T> = { [P in keyof T]: P }
    // So
    KeyOfType<{ a: number, b: string }> == { a: 'a', b: 'b' }
    

    我们可以给这个类型添加一个类型查询来再次获取该类型的所有键。通常一个构造T[keyof T] 获取一个类型的所有属性类型。将其应用于我们的映射类型,它的属性类型与我们基本上返回到 keyof T 的键名相同:

    type KeyOfType<T> = { [P in keyof T]: P }[keyof T]
    // So
    KeyOfType<{ a: number, b: string }> ==  'a'|'b' 
    

    现在我们可以为不总是选择P 添加一个条件类型。由于A | never == A,如果原始属性(T[P])的类型不满足某个约束,我们可以将映射类型中的属性类型设置为never。

    为了表达约束,我们添加了一个额外的通用参数U,并且我们使用了一个具有T extends U ? TypeIfTrue: TYpeIfFalse 形式的条件类型。把它们放在一起,我们得到:

    type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]
    

    【讨论】:

    • 谢谢!它有效,但你能解释一下{...}[keyof T] 部分吗? [keyof T] 是如何工作的?
    • @Joon 抱歉在我的午休时间,希望解释清楚:)
    • 感谢您的精彩解释!我现在明白了!
    • 对象中某项的值类型如何?
    • 哦,nvm,我找到了如何提取值,只是:Pick
    【解决方案2】:

    很棒的解释!!

    我还要补充一点,您可以将默认类型设置为 UT 的任何键,如下所示:

    type Keys<T> = {[P in keyof T]: T[P]}[typeof P]
    
    type KeyOfType<T, U = Keys<T>> = {[P in keyof T]: T[P] extends U ? P : never}[keyof T]
    

    我将U = Keys&lt;T&gt; 添加到KeyOfType 的通用定义中

    谢谢你的解释!

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 1970-01-01
      • 2018-05-30
      • 2021-07-19
      • 2017-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-13
      相关资源
      最近更新 更多