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', ''])
我尝试约束函数参数:
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', ''])