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

如何在TypeScript中实现键值对函数的类型收窄?

问题描述

我想创建一个函数,接收某类型的键及对应取值,处理特定键时执行相应逻辑。实际用在React封装的Table组件里,组件会遍历对象条目并把键值传入单独函数,我需要安全提供自定义覆盖能力。

我简化了代码,定义了User类型和打印用户详情name的函数,但value.name无法被类型收窄,导致访问报错。

代码示例

type User = {
    details: {
        name: string;
    };
    account: {
        status: boolean;
    }
}

const printName =  <K extends keyof User>(key: K, value: User[K]) => {
    if (key === 'details') {
        console.log(value.name); // 无法正常工作
    }
}

const user: User = {
    details: {
        name: 'Bob'
    },
    account: {
        status: true
    }
}

printName('details', user.details);

类型错误信息

Property 'name' does not exist on type '{ name: string; } | { status: boolean; }'.
Property 'name' does not exist on type '{ status: boolean; }'.(2339)
解决方案

TypeScript无法自动通过key的字面量判断收窄value的类型,因为泛型K是keyof User的子集,条件判断无法直接关联泛型参数的具体类型。以下是几种可行的解决方法:

方法1:类型断言

直接在条件块内将value断言为对应类型,简单直接:

const printName =  <K extends keyof User>(key: K, value: User[K]) => {
    if (key === 'details') {
        console.log((value as User['details']).name);
    }
}

方法2:函数重载

通过重载签名明确不同键对应的参数类型,让TypeScript正确推断:

type User = {
    details: { name: string };
    account: { status: boolean };
}

// 重载签名
function printName(key: 'details', value: User['details']): void;
function printName(key: 'account', value: User['account']): void;
// 实现签名
function printName(key: keyof User, value: User[keyof User]): void {
    if (key === 'details') {
        console.log(value.name); // 类型收窄成功
    }
}

const user: User = {
    details: { name: 'Bob' },
    account: { status: true }
}

printName('details', user.details);

方法3:自定义类型守卫

编写类型守卫函数关联key和value的类型,适合复杂场景复用:

type User = {
    details: { name: string };
    account: { status: boolean };
}

function isDetailsEntry<K extends keyof User>(key: K, value: User[K]): value is User['details'] {
    return key === 'details';
}

const printName =  <K extends keyof User>(key: K, value: User[K]) => {
    if (isDetailsEntry(key, value)) {
        console.log(value.name); // 类型收窄成功
    }
}

const user: User = {
    details: { name: 'Bob' },
    account: { status: true }
}

printName('details', user.details);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 22:37:46