简体   繁体   English

如何在typescript中检查function中的类型联合体的类型

[英]How to check the type of a type union in a function in typescript

Say I have this code:说我有这段代码:

interface A {
 type: 'a',
 value : number
}

interface B {
  type: 'b',
  value: string
}

type AB = A | B;

const db: Record<string, AB> = {
  param1: { type: 'a', value: 1234 }
};

I have code like this (over-simplified) that works well我有这样的代码(过度简化)效果很好

function processParameter(parameter: string, expectedType: 'a' | 'b') {
  if (expectedType === 'a') {
    const result = db[parameter];
    if(!result) { throw new Error('Not found'); }
    if(result.type !== 'a') { throw new Error('Unexpected type'); }
    processA(result);
  }
  if (expectedType === 'b') {
    const result = db[parameter];
    if(!result) { throw new Error('Not found'); }
    if(result.type !== 'b') { throw new Error('Unexpected type'); }
    processB(result);
  }
}

function processA(value: A) {
  // ...
}

function processB(value: B) {
  // ...
}

I would like to refactor the code like this:我想像这样重构代码:

function processParameter(parameter: string, expectedType: 'a' | 'b') {
  if (expectedType === 'a') {
    const result = getAndCheck(parameter, expectedType);
    processA(result);
  }
  if (expectedType === 'b') {
    const result = getAndCheck(parameter, expectedType);
    processB(result);
  }
}

// I don't want to write all those lines here, is there a way ?
function getAndCheck(parameter: string, expectedType: 'a'): A;
function getAndCheck(parameter: string, expectedType: 'b'): B;
function getAndCheck(parameter: string, expectedType: 'a' | 'b'): AB {
  const result = db[parameter];
  if(!result) { throw new Error('Not found'); }
  if(result.type !== expectedType) { throw new Error('Unexpected type'); }
  return result;
}

Is there a way to simplify that?有没有办法简化它? Using generic?使用泛型? using inference?使用推理? am I going the wrong way?我走错路了吗?

You can use a generic function to establish a relation between the expectedType parameter and the return type:您可以使用通用 function 在expectedType参数和返回类型之间建立关系:

function getAndCheck<K extends AB['type']>(parameter: string, expectedType: K): Extract<AB, { type: K }> {
    const result = db[parameter] as AB;
    if (!result) { throw new Error('Not found'); }
    if (result.type !== expectedType) { throw new Error('Unexpected type'); }
    return result as Extract<AB, { type: K }>;
}

Playground Link 游乐场链接

Here we use a type parameter K to capture the actual type that is passed in and we ensure that only a type in the union AB can be passed in (we use an index access type to get the union of all possible types).这里我们使用类型参数K来捕获传入的实际类型,并确保只能传入联合AB中的类型(我们使用索引访问类型来获取所有可能类型的联合)。 We then use Extract to get the appropriate element from the union.然后我们使用Extract从联合中获取适当的元素。 (You can read a bit more abotut filtering unions here ) (你可以在这里阅读更多关于过滤联合的内容)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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