记:ts中的类型合并特性

83 阅读2分钟

前言

ts如果联合类型中2个子类型是相似(甚至完全一致),则会有ts类型合并的情况。我们来看一段示例代码:

type ListToolsRequest = {
    id?: string;
}
type ListDiagnosisRequest = {
    id?: string;
}
type CommonRes<T> = {
    code?: string;
    data?: T;
    msg?: string;
}
type ListToolsDataRes = Record<string, string>[];
type ListDiagnosisDataRes = Record<string, string>[];
type ListTools = (...args:ListToolsRequest []) => Promise<CommonRes<ListToolsDataRes>>;
type ListDiagnosis = (...args: ListDiagnosisRequest[]) => Promise<CommonRes<ListDiagnosisDataRes>>;

const listTools: ListTools = (...args) => {
    console.log(1111, args);
     return new Promise((resolve) => resolve({ code:'200', data:[], msg:'测试1'}))
}
const listDiagnosis: ListDiagnosis = (...args) => {
     console.log(1111, args);
     return new Promise((resolve) => resolve({ code:'200', data:[], msg:'测试2'}))
}
let method: ListDiagnosis | ListTools;

enum MethodType {
    DIAGNOSIS = 'diagnosis',
    Tool = 'tool'
}
const fn = (type: MethodType) => {
    if(type === MethodType.DIAGNOSIS){
        method = listDiagnosis;
    }
    if(type === MethodType.Tool){
        method = listTools;
    }

    if(method){
         method().then(res => console.log(res));
    }
}

解读

这段类型代码,我们模拟了2个接口函数类型,分别是ListDiagnosis和ListTools。首先我们定义了ListToolsRequest类型,这个类型为ListTools的参数类型,参数有一个id(当然如果是真实的接口,参数值很少有只有一个的情况,这里只是模拟,只需要一个属性即可),同理ListDiagnosisRequest类型也是。其实我们定义了一个共同的返回值类型,即CommonRes类型,这是一个泛型,泛型T代表的是返回的列表数据类型。随后我们又定义了2个接口函数的列表返回值类型,即ListToolsDataRes和ListDiagnosisDataRes,它们是一个对象数组。随后我们模拟创建了listTools和listDiagnosis,它们2个函数以及对应的类型。

然后,我们定义了method变量,它是一个联合类型,很显然它的值不是listDiagnosis就是listTools。

然后我们定义了一个枚举值,枚举值包含了2个值,最后我们定义了一个函数,函数有一个参数,参数类型就是这个枚举值,然后我们根据传入的type值,来确定调用的是哪个接口函数,最后,我们判断method是否存在值,存在则调用,并得到接口的返回值。

然后请问fn中的method变量的类型应该是怎么样的?

我想大多数人应该跟我一样的想法,即它的类型是ListDiagnosis | ListTools,也就是说它应该是一个联合类型。

当然,这个答案理论上是没有问题的,但是我们忽略了ts的一个特性,那就是类型合并,通过观察,我们其实可以发现ListDiagnosis和ListTools2个类型是相似的(甚至可以说是完全相同),然后ts编译器会将2个子类型进行合并,最终结果应该是ListDiagnosis或者是ListTools(非联合类型)其中的一个。如下图所示:

截屏2024-08-14 下午6.30.39.png

示例代码,可以参考这里

所以如果有读者遇到跟我一样的情况,不必讶异,这就是预期的情况。