如何从Foo接口one属性的key字符串数组生成固定键的Record类型
解决方案:从对象数组的key值生成强类型Record
要实现你想要的强类型约束,关键是让TypeScript保留example中key属性的字符串字面量类型(而不是默认拓宽为宽泛的string),再从中提取出键的联合类型来构建Record。
步骤1:保留key的字面量类型
默认情况下,TypeScript会把对象字面量的字符串属性自动拓宽为string类型,所以我们需要用一些方式让它保留具体的字面量值:
方法A:使用as const + satisfies
既保留字面量类型,又确保对象符合Foo接口的约束:
interface Foo { one: { key: string; /* 更多属性 */ }[] } const example = { one: [{ key: "mykey1" }, {key: "mykey2"}, {key: "mykey3"}] } as const satisfies Foo;
方法B:使用泛型函数
如果不想用断言,也可以通过泛型函数来保留传入对象的字面量类型:
interface Foo { one: { key: string; /* 更多属性 */ }[] } function createFoo<T extends Foo>(foo: T): T { return foo; } const example = createFoo({ one: [{ key: "mykey1" }, {key: "mykey2"}, {key: "mykey3"}] });
步骤2:提取键的联合类型
现在可以从example的类型中,提取出所有key值的字面量联合类型:
// 提取example.one数组中每个元素的key类型,得到"mykey1" | "mykey2" | "mykey3" type ExampleKeys = (typeof example.one[number])['key'];
步骤3:创建强类型的Record
用这个联合类型定义你的A常量,TypeScript会强制要求A的键只能是example中存在的key值:
// 强类型约束:键只能是ExampleKeys,值为string const A: Record<ExampleKeys, string> = { mykey1: "anything", mykey2: "something", mykey3: "another value" }; // 动态赋值场景也能得到类型检查 example.one.forEach(el => { A[el.key] = "updated value"; // 完全合法,因为el.key属于ExampleKeys }); // 尝试赋值不存在的键会直接报错: // A["invalidKey"] = "oops"; // 错误:类型'"invalidKey"'不能赋值给类型'ExampleKeys'
这样就实现了你想要的强类型约束,确保A的键只能是example.one中出现的特定字符串,而不是任意字符串。
内容的提问来源于stack exchange,提问作者Subrato Pattanaik
相关产品推荐
相关产品推荐

