具有一个采用字符串索引对象的通用函数
function wantsStringIndexedObject<
Obj extends { [k: string]: any },
K extends keyof Obj
>(obj: Obj, key: K) {
const _ktype = typeof key
// const ktype: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
const val = obj[key]
wantsStringAndAny(key, val)
// Argument of type 'K' is not assignable to parameter of type 'string'.
// Type 'keyof Obj' is not assignable to type 'string'.
// Type 'string | number | symbol' is not assignable to type 'string'.
// Type 'number' is not assignable to type 'string'.
// (parameter) key: K extends keyof Obj
}
// no error here
wantsStringIndexedObject({
1: 10,
[Symbol()]:1
}, 1)
function wantsStringAndAny(str: string, v:any) {}
我知道我可以在调用key
之前在wantsStringAndAny
上使用类型保护,但是我希望:
1:在key
中肯定要将wantsStringIndexedObject
输入为字符串
2:不应允许使用这种对象调用wantsStringIndexedObject
我想这个问题来自通用定义Obj extends { [k: string]: any }
实际上,使用任何索引类型的任何对象都会扩展具有0个属性的{ [k: string]: any }
。
那么,有没有一种方法可以定义确保字符串索引对象约束的泛型?
答案 0 :(得分:2)
通过使用Extract
条件类型来过滤Obj
的键,可以确保键是字符串类型:
function wantsStringAndAny(str: string, v:any) {
}
function wantsStringIndexedObject<
Obj extends object,
K extends Extract<keyof Obj, string>
>(obj: Obj, key: K) {
const _ktype = typeof key
const val = obj[key]
wantsStringAndAny(key, val)
}
// err
wantsStringIndexedObject({
1: 10,
[Symbol()]:1
}, 1)
//ok
wantsStringIndexedObject({
"1": "",
}, "2")
通常,约束是类型必须实现的最小协定,没有什么可以阻止实际类型在其键中也没有符号。此外,字符串索引实际上将允许同时使用字符串和数字建立索引,因此在您的假设下也可以使用数字。
如果您还想禁止Obj
中的任何数字或符号键,则可以执行以下操作:
function wantsStringIndexedObject<
Obj extends object,
K extends Extract<keyof Obj, string>
>(obj: Obj & Record<Extract<keyof Obj, number | symbol>, never>, key: K) {
const _ktype = typeof key
const val = obj[key]
wantsStringAndAny(key, val)
}
//ok
wantsStringIndexedObject({
"1": "",
}, "1")
wantsStringIndexedObject({
"1": "",
2: 0 // errr
}, "1")
这需要任何number
或symbol
键,并且基本上说它们应该是never
类型(可能,但不太可能),并且任何这样的键都会出错。