假设我有这个代码:
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 }
};
我有这样的代码(过于简化),效果很好
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) {
// ...
}
我想像这样重构代码:
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;
}
有办法简化吗?使用通用?使用推理 ?我是不是走错路了?
最佳答案
您可以使用泛型函数在 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 }>;
}
这里我们使用类型参数K
来捕获传入的实际类型,并确保只能传入联合体AB
中的类型(我们使用 index access type 来获取所有可能类型的并集)。然后,我们使用 Extract
从联合中获取适当的元素。 (您可以阅读更多关于过滤联合的信息 here )
关于typescript - 如何在 typescript 中检查函数中类型联合的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71600840/