首页 > 解决方案 > 具有 T 和 K 类型参数的泛型函数,其中 K 是 T 的 keyof 和一个数组?

问题描述

在 typescript 中,可以声明一个函数,该函数需要一个类型及其一个键作为参数:

function foo<T, K extends keyof T>(object: T, key: K)

在函数体中,您可以获取或设置 的object键值,甚至提取键的类型 ( T[k]):

function setter<T, K extends keyof T>(object: T, key: K){
  return (value: T[K]) => {
    obj[key] = value;
  };      
}

function logger<T, K extends keyof T>(object: T, key: K){
  console.log(obj[key]);   
}

问题:

是否有可能具有泛型类型K并且extends keyof T是数组?(换句话说:K必须是一个数组和一个类型的键T

示例用例:

function lengthLogger<T, K /*extends keyof T and is array*/>(object: T, key: K){
  console.log(object[key].length)     
}

标签: functiontypescriptgenerics

解决方案


有几种方法可以做到这一点。最好的方法是声明TKany[]

function lengthLogger<T extends Record<K, any[]>, K extends keyof T>(object: T, key: K) {
    console.log(object[key].length)
}

lengthLogger({
    foo: "",
    bar: ["", ""]
}, 'bar')

lengthLogger({
    foo: "",
    bar: ["", ""]
}, 'foo') // Error

这提供了调用站点和声明类型的安全性。

您会发现另一种选择是使用条件类型K仅提取特定类型的属性。这适用于调用站点,但您将需要声明的类型断言:

type ExtractKeysOfType<T, TValue> = { [P in keyof T]: T[P] extends TValue ? P : TValue}[keyof T]
function lengthLogger<T , K extends ExtractKeysOfType<T, any[]>>(object: T, key: K) {
    console.log((object as any)[key].length)
}

lengthLogger({
    foo: "",
    bar: ["", ""]
}, 'bar')

lengthLogger({
    foo: "",
    bar: ["", ""]
}, 'foo') // Error

推荐阅读