TypeScript可以将keyof限制为特定类型的属性列表吗?

时间:2020-02-18 23:40:56

标签: typescript generics

所以,我想编写一个通用方法。出于问题的原因,假设我要连接来自同一类型的2个不同对象的2个字符串属性。

function concat<T>(target1: T, target2: T, key: keyof T): string {
  return target1[key] + target2[key];
}

以上内容无法编译,因为编译器没有迹象表明我想将key限制为仅string类型的属性列表。

TypeScript当前不支持此功能吗?

我知道我可以进行运行时检查,但是我希望对此进行编译时检查。

1 个答案:

答案 0 :(得分:2)

您要在此处使用三个通用参数。每个输入一个,按键一个。

type CommonKey<A, B> = keyof A & keyof B

function concat<A, B, K extends CommonKey<A, B>>(
  target1: A,
  target2: B,
  key: K
): string {
  return `${target1[key]}${target2[key]}`
}

这将密钥定义为A和B的密钥,这意味着它必须同时满足这两个密钥。


要将其进一步限制为仅字符串值,您需要使用带有条件的映射类型来测试其类型。

// This type returns all keys that have a value of type string
type StringKeyOf<T> = {
    // for all keys in T
    [K in keyof T]:

        // if the value of this key is a string, keep it. Else, discard it
        T[K] extends string ? K : never

// Get the union type of the remaining values.
}[keyof T]

// Only allow common keys of both objects.
type CommonKey<A, B> = StringKeyOf<A> & StringKeyOf<B>

function concat<
    A,
    B,
    K extends CommonKey<A, B>
>(target1: A, target2: B, key: K): string {
    return `${target1[key]}${target2[key]}`
}

现在,这将产生类型错误,因为age是一个数字。

concat(
    { name: 'a', age: 12 human: 'maybe?' },
    { name: 'b', age: 8, dog: true },
    'age' // Type error

)
相关问题