TypeScript中如何用字符串访问只读对象并指定返回类型?
TypeScript字符串索引对象属性的类型问题
问题1:简单对象字符串索引的类型处理
在TypeScript中用字符串访问对象属性时遇到类型错误:
const parent2 = {child: 'name'} const index2: string = 'child'; const child3 = parent2[index2]
报错信息:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ child: string; }'.
No index signature with a parameter of type 'string' was found on type '{ child: string; }'
需要简便方法让parent2[index2]返回'name' | undefined类型。
问题2:嵌套只读对象的字符串索引访问
处理嵌套只读对象时手动构造allowStringIndex类型来支持字符串索引并保留自动补全,但过程十分繁琐,想找简便方法实现nestedObject[grandParentIndex]?.[parentIndex]这样的访问:
const nestedObject = {grandParent: {name: 'grandparent', parent: {name: 'parent', child: {name: 'child'}}}} as const; type child = {name: 'child', [key: string]: 'child' | undefined} type parent = {name: 'parent', child: child} type overrideParent = parent & {[key: string]: parent[keyof parent] | undefined} type grandParent = {name: 'grandparent', parent: overrideParent} type overrideGrandParent= grandParent & {[key: string]: grandParent[keyof grandParent] | undefined} type allowStringIndex = {grandParent: overrideGrandParent} & {[key: string]: overrideGrandParent | undefined} const castedObject = nestedObject as allowStringIndex; const grandParentIndex: string = 'grandparent'; const parentIndex: string = 'parent' const child = nestedObject[grandParentIndex]?.[parentIndex]?.['child'] const parent1 = castedObject[grandParentIndex]?.[parentIndex]
尝试过递归类型,但效果不理想。
解决方案
针对问题1:简单对象的类型适配
定义通用工具类型,给原对象类型添加字符串索引签名,同时保留原有属性的精确类型:
type AllowStringIndex<T> = T & { [key: string]: T[keyof T] | undefined }; const parent2 = {child: 'name'} const index2: string = 'child'; // 类型断言为适配后的类型 const child3 = (parent2 as AllowStringIndex<typeof parent2>)[index2]; // child3的类型为 'name' | undefined
如果不需要自动补全,也可以直接在定义对象时添加索引签名,但会丢失属性补全能力:
const parent2: { child: string; [key: string]: string | undefined } = {child: 'name'} const index2: string = 'child'; const child3 = parent2[index2]; // 类型为 string | undefined
针对问题2:嵌套只读对象的递归类型适配
编写递归通用工具类型,自动给嵌套对象的每一层添加字符串索引签名:
type RecursiveAllowStringIndex<T> = T extends Record<string, unknown> ? T & { [key: string]: RecursiveAllowStringIndex<T[keyof T]> | undefined } : T; const nestedObject = {grandParent: {name: 'grandparent', parent: {name: 'parent', child: {name: 'child'}}}} as const; // 转换类型 const castedObject = nestedObject as RecursiveAllowStringIndex<typeof nestedObject>; const grandParentIndex: string = 'grandparent'; const parentIndex: string = 'parent'; const parent1 = castedObject[grandParentIndex]?.[parentIndex]; // parent1的类型为 { readonly name: "parent"; readonly child: { readonly name: "child"; }; } | undefined const child = castedObject[grandParentIndex]?.[parentIndex]?.['child']; // child的类型为 { readonly name: "child"; } | undefined
该递归类型会自动遍历对象每一层,给每个对象类型添加字符串索引签名,同时保留原有属性的只读特性和精确类型,也支持自动补全。
内容的提问来源于stack exchange,提问作者Clifford B. Wolfe
相关产品推荐
相关产品推荐

