Typescript接口上的动态属性键和值取决于其他字段

时间:2020-03-13 03:05:29

标签: typescript

我是Typescript的新手,我想知道是否有一种方法可以完成以下任务:

我想输入一些要通过它们的两个不同端点发送给Hubspot的属性,这些API中的每一个均使用名为property的键来输入数据,而另一个称为name的键。 这意味着它们可以如下所示:

{
  property: 'email',
  value: 'test@email.com'
}

或者:

{
  name: 'email',
  value: 'test@email.com'
}

然后,我想验证我仅发送了一些特定字段。这样说:

export interface HubspotFields {
  newsletter: boolean;
  name: string;
  email: string;
}

那么,有没有办法做这样的事情?:

export interface Test {
  [either "property" or "name"]: [keyof HubspotFields (value can only be one of the keys from HubspotFields)];
  value: [the type of the corresponding dynamic keyof HubspotFields (string 
 boolean)];
}

换句话说:

//This fails
{
  something: 'email',
  value: 'test@email.com'
}
//This fails
{
  property: 'something',
  value: 'test@email.com'
}
//This fails
{
  property: 'email',
  value: 2312
}
//This passes
{
  property: 'newsletter',
  value: true
}
//This passes
{
  name: 'email',
  value: 'test@email.com'
}

希望我要完成的任务很明确,如果不能,我很乐于详细说明。预先感谢!

1 个答案:

答案 0 :(得分:0)

我认为,以下类型可以满足您的需求:

// ensure return type of boolean or string
type StringOrBoolReturn = {
  [K: string]: boolean | string
}

export interface HubspotFields extends StringOrBoolReturn {
  newsletter: boolean;
  name: string;
  email: string;
}

// support either property XOR name
type ApiData<K extends keyof HubspotFields = keyof HubspotFields> = {
  property: K
  name?: never
  value: HubspotFields[K]
} | {
  property?: never
  name: K
  value: HubspotFields[K]
}
function sendApiData<K extends keyof HubspotFields>(data: ApiData<K>) {/*... logic ...*/}

sendApiData({ something: 'email', value: 'test@email.com' }) // ✖
sendApiData({ property: 'something', value: 'test@email.com' }) // ✖
sendApiData({ property: 'email', value: 2312 }) // ✖
sendApiData({ name: 'email', property: "email", value: 'test@email.com' })  // ✖
sendApiData({ property: 'newsletter', value: true }) // ✔
sendApiData({ name: 'email', value: 'test@email.com' })  // ✔
sendApiData({ name: 'email', value: 'test@email.com' })  // ✔