[英]Typescript function arguments based on types with enums as keys
[英]Limiting keys based on value types in TypeScript
我需要一种setProperty
函数,它允许在对象上设置属性,但将它们限制为string
类型的属性。
似乎我已经想出了如何将允许的键限制为具有K
值类型的键,但 TypeScript 似乎并没有完全识别出这一点。 这是我所拥有的:
type KeysMatching<T, V> = {
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T];
function bindChange<C, K extends KeysMatching<C, string>>(
container: C,
key: K,
): (ev: KeyboardEvent) => void {
return (ev: KeyboardEvent) =>
// @ts-ignore how do we tell typescript container[key] is a string?
(container[key] = (ev.target! as HTMLInputElement).value);
}
const sample = {
foo: 'bar',
baz: 42,
};
// this is correctly allowed
bindChange(sample, 'foo');
// this is correctly rejected
//bindChange(sample, 'baz');
我想弄清楚的是,是否有更好的方法可以消除对@ts-ignore
的需求。
平心而论,该函数不是 100% 类型安全的,无法确保container[key]
不是string
的子类型。 约束只是最低要求,实际类型可以更具体。 考虑一下:
const sample = {
foo: 'bar',
baz: 42,
} as const
// this is correctly allowed
bindChange(sample, 'foo'); // but 'foo' is of type 'bar' but is assigned a string
问题是,通常 Ts 并没有真正对仍然具有未解析类型参数的条件类型进行大量推理。 所以很多时候泛型函数的实现都会以类型断言告终。 不要担心太多 IMO。
由于无法确保所有属性都是字符串,如果您认为这种极端情况不重要,唯一的解决方案是使用类型断言:
function bindChange<C, K extends KeysMatching<C, string>>(
container: C,
key: K,
): (ev: KeyboardEvent) => void {
return (ev: KeyboardEvent) =>
(container[key] = (ev.target! as HTMLInputElement).value as unknown as C[K]);
}
还有这个版本,它确实解决了这个问题,但失去了函数调用的智能感知,这在我看来更重要:
type KeysMatching<T, V> = {
[K in keyof T]: T[K] extends V ? K : never;
}[keyof T];
function bindChange<C extends Record<K, string>, K extends PropertyKey>(
container: C,
key: K,
): (ev: KeyboardEvent) => void {
return (ev: KeyboardEvent) =>
(container[key] = (ev.target! as HTMLInputElement).value as unknown as C[K]);
}
const sample = {
foo: 'bar',
baz: 42,
};
// this is correctly allowed
bindChange(sample, 'foo');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.