我使用以下代码来验证在特定对象上只能访问现有密钥:
function prop<O, K extends keyof O>(key: K, obj: O) {
return obj[key];
}
这足够好,并且在使用以下代码时可以正常工作:
const obj = { foo: 'bar' };
prop('foo', obj); // ok
prop('bar', obj); // error
但是,我想将代码重构为如下所示:
const obj = { foo: 'bar' };
prop('foo')(obj); // should be ok
prop('bar')(obj); // should error
我的第一个想法是按如下所示重新构造函数:
function prop<O, K extends keyof O>(key: K) {
return function inner(obj: O) {
return obj[key];
}
}
但是,这不起作用,并产生以下错误:
类型'“ foo”'的参数不能分配给类型的参数 “从不”。
这对我来说很有意义,因为在验证密钥后该对象不可用。
因此,我的目标是在将对象传递到第二个函数中时,将验证逻辑从“检查对象中是否存在键”翻转为“检查对象中是否包含键”,并且错误如果没有,则对对象进行类型验证,此时没有其他约束。
使用TypeScript似乎应该可以做到这一点,但是我还没有找到一种使用完全动态的键和对象来实现此目的的方法,对象的唯一条件是存在给定的键。
答案 0 :(得分:4)
由于尚未设置O
,因此您不能在第一个函数调用中将其作为参数使用(无法从中推断出它)。您当然可以手动指定它,但这并不理想。
另一个选择是在第二个函数上使用O
参数。第一次呼叫将指定K
(作为密钥,任何密钥)。第二个调用将指定O
,约束为O
必须具有任何类型的密钥K
。
function prop<K extends keyof any>(key: K) {
return function inner<O extends Record<K, any>>(obj: O) : O[K]{
return obj[key];
}
}
const obj = { foo: 'bar' };
prop('foo')(obj); // be ok, returns string
prop('bar')(obj); // is error
答案 1 :(得分:1)
如果您愿意手动指定通用名称,则可以执行以下操作:
function prop<O>(key: keyof O) {
return function inner(obj: O) {
return obj[key];
}
}
prop<{ prop: string }>('prop')({ prop: 'test'}) // compiles
prop<{ prop: string }>('prop')({ wrong: 'test'}) // error
答案 2 :(得分:1)
将类型参数放在开头:
const prop = <T>(property: keyof T) =>
(source: T) =>
source[property];
为了最大程度地保证类型安全,请在调用prop
时提供type参数:
const prop = <T, K extends keyof T = keyof T>(property: K) =>
(source: T): T[K] =>
source[property];
prop<typeof obj>('foo')(obj); // $ExpectType string
prop<typeof obj>('bar')(obj); // $ExpectError
答案 3 :(得分:0)
你还好吗?
export function hasProp<T extends object>(obj: T, prop: string): boolean {
return (obj as any)[prop] !== undefined;
}
您还可以使用Object.keys()