繁体   English   中英

根据 TypeScript 中的值类型限制键

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM