TS:具有键映射的通用参数默认值

TS : Generic parameter defaults with key mapping

我尝试约束函数参数:

interface MyList {
  color: string
  static: boolean
  ...
}

create <T, K extends keyof T, V extends T[K]> (arg: [K, V]) {}

但电话看起来像

create<MyList, 'color', string>(['color', 'red'])

所以我尝试使用默认泛型类型:

create <T, K extends keyof T = keyof T, V extends T[K] = T[K]> (arg: [K, V]) {}
create<MyList>(['color', false]) // <- no error because ['color|static', 'string|boolean']

但它不再起作用了。

第二种方法的问题在于,如果您指定类型参数的值,则不会对该参数进行推断,因此 K 将是所有键的并集 color | static | ...,因此 T[K] 将是所有 属性 类型的联合。

您可以执行以下操作:

function create <T, K  extends keyof T> (arg: [K, T[K]]) {}

create<MyList, 'color'>(['color', ''])
create<MyList, 'color'>(['color', true]) //error

它仍然有点冗长,但您不需要指定 属性 类型,它会被正确输入。

或者您可以使用双函数方法首先锁定 T,然后让编译器推断 K

function create <T>() {
    return function <K  extends keyof T> (arg: [K, T[K]]) {

    }
} 

create<MyList>()(['color', ''])
create<MyList>()(['color', true]) //error

或者如果 create 是泛型 class 的成员,那么这个问题就会消失:

class Creator<T> {
    create<K extends keyof T>(arg: [K, T[K]]) {

    }
}
let creator = new Creator<MyList>();
creator.create(['color', ''])
creator.create(['color', true]) //error

编辑

正如评论中所讨论的,您想要任意数量的 key/value 对并正确检查它们。你不能对任意数量的参数执行此操作,但你可以为最多 n 对定义重载,例如 3。如果你调用更多,你将收到错误,因此你将知道是时候添加更多重载了:

class Creator<T> {
    create<K1 extends keyof T, K2 extends keyof T, K3 extends keyof T>(arg1: [K1, T[K1]], arg2: [K2, T[K2]], arg3: [K3, T[K3]]): void
    create<K1 extends keyof T, K2 extends keyof T>(arg1: [K1, T[K1]], arg2: [K2, T[K2]]): void
    create<K1 extends keyof T>(arg: [K1, T[K1]]): void
    // Implementation sigature, not directly callable 
    create<K extends keyof T>(...arg: [K, T[K]][]) {

    }
}
let creator = new Creator<MyList>();
creator.create(['color', ''])
//Works for up to 3 items
creator.create(['color', ''], ['color', ''], ['color', '']) 
// Is an error if there are more so you will know to add more overloads
creator.create(['color', ''], ['color', ''], ['color', ''], ['color', ''])