如何用TypeScript约束defaultProperty为properties的有效键?
问题:限制defaultProperty必须为properties的有效键
需求是创建一个TypeScript类型,确保defaultProperty的值必须是properties对象的有效键。以下是原始示例:
type TestType = { properties: { [x: string]: number; }; defaultProperty: string; }; // 不符合要求但未报错 const invalid: TestType = { properties: { foo: 123, }, defaultProperty: "not a valid property", }; // 符合要求 const valid: TestType = { properties: { foo: 123, }, defaultProperty: "foo", };
上述代码中,invalid的defaultProperty不是properties的有效键,但TypeScript没有报错。尝试过以下泛型方案,但未达到预期:
type TestType<P = { [p: string]: number }> = { properties: P; defaultProperty: keyof P; };
该方案既不会对invalid报错,还会让defaultProperty的类型变为string | number,不符合需求。
解决方案
要实现需求,核心是让TypeScript根据具体的properties对象推断出键的类型,而非使用宽泛的索引签名默认值。以下是两种可行方式:
方式一:泛型函数(推荐)
通过函数创建对象时,TypeScript会自动推断properties的键类型,从而严格约束defaultProperty:
function createConfig<P extends Record<string, number>>(config: { properties: P; defaultProperty: keyof P; }) { return config; } // 报错:类型'"not a valid property"'不能赋值给类型'"foo"' const invalid = createConfig({ properties: { foo: 123 }, defaultProperty: "not a valid property" }); // 正常通过 const valid = createConfig({ properties: { foo: 123 }, defaultProperty: "foo" });
方式二:泛型类型+显式指定参数
如果需要直接定义变量,可以使用泛型类型,但必须显式指定泛型参数,让TypeScript明确properties的键集合:
type TestType<P extends Record<string, number>> = { properties: P; defaultProperty: keyof P; }; // 报错:类型'"not a valid property"'不能赋值给类型'"foo"' const invalid: TestType<{ foo: number }> = { properties: { foo: 123 }, defaultProperty: "not a valid property" }; // 正常通过 const valid: TestType<{ foo: number }> = { properties: { foo: 123 }, defaultProperty: "foo" };
原泛型方案无效的原因
你之前的泛型给了默认值{ [p: string]: number },当未指定泛型参数时,TypeScript会使用这个默认值。而keyof { [p: string]: number }的结果是string | number(因为JS对象键会被隐式转换为字符串或数字),所以无法约束无效键的输入。
内容的提问来源于stack exchange,提问作者Yanick Rochon
相关产品推荐
相关产品推荐

