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

TypeScript中通过辅助函数获取嵌套属性时如何保留类型?

TypeScript属性提取函数的类型安全实现(保留返回值类型)

你现在的函数因为使用as keyof CardFace强制类型转换,导致TypeScript无法自动推导精准的返回值类型,只能返回所有可能类型的联合。要解决这个问题,我们可以通过两种方式实现类型保留:函数重载或泛型条件类型。

方案一:函数重载(直观贴合规则)

函数重载可以明确不同输入场景对应的返回值类型,让TypeScript精准匹配逻辑分支:

interface CardFace {
  name: string;
  age: number;
}

// 把Card定义为联合类型,严格符合"要么有card_faces,要么有name/age"的规则
type Card = 
  | { id: string; name: string; age: number }
  | { id: string; card_faces: CardFace[] };

// 重载1:card包含card_faces且key是CardFace属性时,返回CardFace对应类型
function getPropertyByKey<K extends keyof CardFace>(card: { card_faces: CardFace[] }, key: K): CardFace[K];
// 重载2:key不属于CardFace或card无card_faces时,返回Card对应类型
function getPropertyByKey<K extends keyof Card>(card: Card, key: K): Card[K];
// 核心实现
function getPropertyByKey<K extends keyof Card>(card: Card, key: K) {
  if (card.card_faces?.[0] && key in card.card_faces[0]) {
    return card.card_faces[0][key as keyof CardFace];
  }
  return card[key];
}

// 测试用例
const card1 = {
  id: "1",
  name: "Thomas",
  age: 32,
} satisfies Card;

const card2 = {
  id: "2",
  card_faces: [
    { name: "Ario", age: 15 },
    { name: "Ario Evolved", age: 27 },
  ],
} satisfies Card;

const card1age = getPropertyByKey(card1, "age"); // 类型:number
const card2name = getPropertyByKey(card2, "name"); // 类型:string
const card2id = getPropertyByKey(card2, "id"); // 类型:string

这里将Card定义为联合类型,严格匹配题目中的规则;通过两个重载签名,TypeScript会根据传入的参数自动匹配对应的类型,返回精准的结果,不再需要模糊的联合类型。

方案二:泛型条件类型(兼容更灵活的Card结构)

如果你的实际场景中允许Card同时存在card_faces和name/age,可以用泛型结合条件类型来实现灵活的类型推导:

interface CardFace {
  name: string;
  age: number;
}

interface Card {
  id: string;
  name?: string;
  age?: number;
  card_faces?: CardFace[];
}

// 条件类型:根据card结构和key类型推导返回值
type GetPropertyType<C extends Card, K extends keyof Card> = 
  K extends keyof CardFace 
    ? C extends { card_faces: CardFace[] } 
      ? CardFace[K] 
      : C[K]
    : C[K];

const getPropertyByKey = <C extends Card, K extends keyof Card>(card: C, key: K): GetPropertyType<C, K> => {
  if (card.card_faces?.[0] && key in card.card_faces[0]) {
    return card.card_faces[0][key as keyof CardFace] as GetPropertyType<C, K>;
  }
  return card[key] as GetPropertyType<C, K>;
};

// 测试用例
const card1 = {
  id: "1",
  name: "Thomas",
  age: 32,
};

const card2 = {
  id: "2",
  card_faces: [
    { name: "Ario", age: 15 },
    { name: "Ario Evolved", age: 27 },
  ],
};

const card1age = getPropertyByKey(card1, "age"); // 类型:number | undefined(因Card中age为可选属性)
const card2name = getPropertyByKey(card2, "name"); // 类型:string
const card2id = getPropertyByKey(card2, "id"); // 类型:string

GetPropertyType通过多层条件判断,先检查key是否属于CardFace,再判断card是否包含有效的card_faces,最终返回对应的类型。实现中需要用类型断言帮助TypeScript确认返回值符合条件类型的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 19:32:18