You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript如何让unWrap函数返回推导后类型而非类型表达式?

问题描述

我在编写TypeScript代码时实现了一个unWrap()函数,用于将带有嵌套Ref类型的属性转换为对应原始类型。代码如下:

interface Ref<T = any> {
    value: T;
}

type UnwrapRef<T extends object> = {
    [K in keyof T]: T[K] extends Ref<infer V> ? V : T[K];
};

function wrap<T extends unknown>(val: T): Ref<T> {
    return {
        value: val,
    };
}

function unWrap<T extends object>(val: T) {
    for (let key in val) {
        if ((val[key] as any).value !== undefined) {
            val[key] = (val[key] as any).value;
        }
    }
    return val as UnwrapRef<T>;
}

// 这里type_test能正确展开为明确类型
type type_test = UnwrapRef<{
    foo: number;
    bar: Ref<{
        baz: number;
    }>;
}>;

// 但res的类型提示还是UnwrapRef<原始类型表达式>,而非展开后的明确类型
const res = unWrap({
    foo: 1,
    bar: wrap({
        baz: 10,
    }),
});

基础逻辑运行正常,UnwrapRef能正确推导出type_test的最终展开类型,但变量res的类型提示仍为原始的类型表达式,而非像type_test那样的展开后的明确结果,尽管自动补全功能正常。想知道有没有办法让res的类型提示更简洁美观?

解决方案

要让TypeScript在类型提示中展开UnwrapRef的结果,可以通过以下方式实现:

1. 新增Prettify工具类型强制展开嵌套类型

定义一个专门用于触发类型展开的工具类型,让TypeScript显示扁平化的最终类型结构:

type Prettify<T> = {
    [K in keyof T]: T[K];
} & {};

修改UnwrapRef的定义,用Prettify包裹结果:

type UnwrapRef<T extends object> = Prettify<{
    [K in keyof T]: T[K] extends Ref<infer V> ? V : T[K];
}>;

此时res的类型提示会自动展开为:

const res: {
    foo: number;
    bar: {
        baz: number;
    };
}

2. 直接在unWrap函数返回时处理类型

如果不想修改UnwrapRef,也可以在函数返回时用Prettify处理返回类型:

function unWrap<T extends object>(val: T) {
    for (let key in val) {
        if ((val[key] as any).value !== undefined) {
            val[key] = (val[key] as any).value;
        }
    }
    return val as Prettify<UnwrapRef<T>>;
}

原理说明

TypeScript默认会保留类型别名、映射类型的原始表达式,而Prettify通过重新映射属性并交叉空对象,触发TypeScript的类型展开逻辑,从而在编辑器提示中显示扁平化的最终类型。

内容的提问来源于stack exchange,提问作者Aiysosis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 08:10:17