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
相关产品推荐
相关产品推荐

