对于密钥及其类型,使用通用密钥进行集合操作

时间:2017-10-04 01:13:52

标签: typescript

很难用清晰的语言解释这一点。

在下面的Setter界面中,我将'field'键的类型限制为keyof Store(在这种情况下'name'|'age')。

然后对于'value'键,我想获得给定'field'键的值的类型。

  • 因此,如果'field'是'name','value'必须是一个字符串。
  • 并且,如果'field is'age','value'必须是一个数字。

这就是我现在所拥有的:

interface Store {
  name: string,
  age: number
}
interface Setter<T = Store, K extends keyof T> {
  type: 'SET_VALUE',
  field: K
  // for key: 'name', want type value: string
  // for key: 'age', want type value: number
  value: T[K]
}

// Should error
const invalidName: Setter = {
  type: 'SET_VALUE',
  field: 'name',
  value: 30,
}

// Should work
const validName: Setter = {
  type: 'SET_VALUE',
  field: 'name',
  value: 'hello',
}

// Should work
const validAge: Setter = {
  type: 'SET_VALUE',
  field: 'age',
  value: 30,
}

2 个答案:

答案 0 :(得分:2)

通用T没有为您做任何事情,因为您始终希望它为Store。因此,您应该首先删除T泛型,并将T的实例替换为Store

interface Store {
  name: string,
  age: number
}

interface Setter<K extends keyof Store> {
  type: 'SET_VALUE',
  field: K
  value: Store[K]
}

接下来,您希望Setter成为existential type,这意味着您只需要声明某个没有类型参数的Setter,而TypeScript会将其解释为某些K满足type参数,而不必指定它。好吧,TypeScript没有存在类型(没有疯狂的解决方法)所以你不能这样做。

可以做的是做一个帮助函数,它为你提供一个对象字面值,并且推断类型为K,所以你没有把它写出来:

function asSetter<K extends keyof Store>(setter: Setter<K>): Setter<K> {
  return setter;
}

让我们看看它的实际效果:

// error as desired
const invalidName = asSetter({
  type: 'SET_VALUE',
  field: 'name',
  value: 30,
});

// works, inferred as Setter<'name'>
const validName = asSetter({
  type: 'SET_VALUE',
  field: 'name',
  value: 'hello',
});

// works, inferred as Setter<'age'>
const validAge = asSetter({
  type: 'SET_VALUE',
  field: 'age',
  value: 30,
});

希望有所帮助!

答案 1 :(得分:1)

以下作品:

class Setter<K extends keyof T, T = Store> {
  constructor(public field: K, public value: T[K]) { }
  type: 'SET_VALUE'
}

const anotherValidName = new Setter('name', 'thename')
const anotherValidAge = new Setter('age', 30)

您也可以在不使用类复制密钥的情况下执行此操作:

var span = $('span');
span.remove();
$('li').prepend(span);